Namespaces are one honking great idea

Steven D'Aprano steve at pearwood.info
Fri Jul 1 13:46:40 EDT 2016


On Sat, 2 Jul 2016 12:49 am, BartC wrote:

> On 01/07/2016 15:13, Steven D'Aprano wrote:
> 
>> Sometimes we have a group of related functions and variables that belong
>> together, but are not sufficiently unrelated to the rest of the module
>> that we want to split them out into another file.
> 
>> Here's a proof of concept. I use a class with a custom metaclass like
>> this:
>>
>>
>> # Python 3 version
>> class ExampleNS(metaclass=Namespace):
>>     x = 1
>>     y = []
>>
>>     def spam(n):
>>         return 'spam'*n
> 
>> py> Example.spam(5)
>> 'spamspamspamspamspam'
> 
> 
> Why not just extend the capabilities of a class? 

The usual ways to change the behaviour of classes from Python code is via
decorator, which lets you modify the class after it is created, a
metaclass, which lets you modify it before it is created, or by using
descriptors to customize attribute access.

I'm using a metaclass. When you write:

class K: ...

that is syntactic sugar for calling the default metaclass (`type`) with some
arguments, and `type` then returns the new class K. But if you use a
metaclass (usually, but not necessarily a subclass of `type`) you can
customize the creation of the new class, or even return a completely
different object altogether. That's what I'm doing.

Why am I returning a module instead of a class? Because (1) conceptually a
namespace (in the C++ sense) is like a module; (2) classes have a whole lot
of expectations that aren't relevant to namespaces (like inheritance,
instantiation, "is-a", etc); and (3) it's easy to use a module, which
already provides most of the behaviour I want.


> I actually thought this 
> would work until I tried it and it didn't:
> 
> class C():
>      def fn():
>          print ("Hi!")
> 
> C.fn()

That actually will work in Python 3. (I had forgotten that.) In Python 2,
you have to inherit C from object, AND decorate fn with staticmethod:

class C(object):
    @staticmethod
    def fn():
        print ("Hi!")


But for my use, that's not enough. I want this to work:

class Foo:
    def f():
        return g().upper()
    def g():
        return "hi!"


That is, Foo should behave as if it were a module imported from a file,
except without actually being imported from a file.




-- 
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list