Namespaces are one honking great idea

Steven D'Aprano steve at pearwood.info
Sat Jul 2 23:44:46 EDT 2016


On Sun, 3 Jul 2016 01:34 am, Kevin Conway wrote:

> staticmethod isn't technically required to use a method through the class
> (or subclasses), it simply provides the appropriate magic to allow it to
> be called through instances.
> 
> For example, the following code covers all described use cases of the
> proposed namespace. 

It really doesn't. Here's your class:

> Methods are invoked without creating instances and 
> state is managed on the class object directly.
> 
> class CustomNs:
> 
>     stateful_data = 1
> 
>     @staticmethod
>     def echo(text):
>         print(text)
> 
>     @classmethod
>     def mutate(cls):
>         cls.stateful_data += 1
>         print(cls.stateful_data)


The class scope is not "first class" (pun intended), as you cannot refer to
class-level variables without prefixing them with the class, even from
within the class.

Although the class *may* be used without instantiating, this violates the
user's expectations and may be confusing.

I acknowledge that my own namespace has a similar problem, as it uses the
class keyword, but the use of an explicit Namespace decorator or metaclass
gives a hint that something is different. And if you try calling the
Namespace, as if to instantiate it, you get a TypeError.


[...]
> For the proponents of namespace, what is deficient in the above example
> that necessitates a language change?

It's not a language change. Although I'd like a new keyword, to avoid
the "but it looks like a class" problem, its not necessary.


Try getting this behaviour from within a class:


class Food(metaclass=Namespace):

    # (1) no special decorators required
    def spam(n):
        return ' '.join(['spam']*n)

    # (2) can call functions from inside the namespace
    breakfast = spam(5)

    # (3) no "cls" or "self" argument
    def lunch():
        # (4) can access variables using their undotted name
        return breakfast + ' and eggs'

    def supper():
        # (5) likewise functions (a special case of #4)
        return lunch() + ' and a fried slice of spam'

    def mutate(n):
        # global inside the namespace refers to the namespace,
        # not the surrounding module
        global breakfast
        breakfast = spam(5)



Everything written inside the namespace object could have started as top
level module code. I select the code, hit my editor's "Indent" command, and
insert a single line at the top to turn it into a namespace.

If I decide to move the code into a separate file, I just copy the block,
excluding the "class ... metaclass" header line, past into a new file,
select all, and Dedent. Done.

Can you do all of that with an ordinary class?





-- 
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