Namespaces are one honking great idea

Steven D'Aprano steve at pearwood.info
Mon Jul 4 22:34:44 EDT 2016


On Mon, 4 Jul 2016 09:23 pm, jmp wrote:

> On 07/01/2016 04:13 PM, Steven D'Aprano wrote:
>> But classes are not like the others: they must be instantiated before
>> they can be used, and they are more than just a mere namespace grouping
>> related entities. Classes support inheritance. Classes should be used for
>> "is-a" relationships, not "has-a" relationships. Although classes (and
>> instances) are namespaces, they provide fundamentally different kind of
>> behaviour than modules and packages.
> 
> A namespace would not hurt but I really don't get why you don't consider
> classes a valid and rather helpful namespace.

I never said that.

This is where the term "namespace" can be ambiguous. "Namespace" can refer
to any of:

- an abstract mapping of symbols (names) to values;

- specific kinds of namespaces:

  * the concrete C++/C#/PHP data type called "namespace";
  * Python packages and modules;
  * classes;
  * instances of a class;

- the implementation (the __dict__ attribute of modules, classes);

etc. Now clearly a class is not the same thing as the class __dict__, and a
module is not the same as a class, and neither modules nor classes are the
same as a C++ namespace. Doesn't mean that classes aren't valid namespaces,
just that their semantics, use-cases and behaviour are different to those
of modules.



> 1/ classes do not have to be instantiated.

That's a bit of a sore point to me.

Some years ago I wrote here to ask what name is given to a class that is not
instantiated before being used. Singleton classes get instantiated once,
allowing a single instance. What if you had a class that didn't need
instantiating at all, so that the class itself was *effectively* the
singleton? What should that be called?


Instead of this:

    class SingletonClass:
        ...

    singleton = SingletonClass()
    singleton.method()


what if we had this instead?

    class singleton:
        ...

    singleton.method()


I was roundly told that this was crazy talk, that the whole point of classes
was that they must be instantiated to use them, that code like the second
example would be confusing and very possibly bring about the fall of
Western Civilisation. The idea that this might be a legitimate alternative
to the singleton design pattern was dismissed.

(The Python community is terribly conservative when it comes to code.)

And, in a sense, they were right: there are two common ways to get
singleton-like behaviour in general, and in Python specifically:

- use class that allows only a single instance;

- use a module.

Using the class itself is unusual and surprising (especially to Java
programmers, where classes aren't even first-class values), and more so,
it's *inconvenient*.

To write a class which is used without instantiation, you should raise an
error on instantiation, decorate every method using classmethod or
staticmethod, and have methods have to call each other using the dotted
name:

class Example:
    var = 999

    def __init__(self):
        raise TypeError('do not instantiate this class')

    @classmethod
    def spam(cls, arg):
        return cls.eggs(arg) + cls.var

    @classmethod
    def eggs(cls, arg):
        return arg*2


*** IF *** you are willing to push the code out into its own separate .py
file, you can use a module and write your code in a more natural form:


# module example.py
var = 999

def spam(arg):
    return eggs(arg) + var

def eggs(arg):
    return arg*2


What I'm calling a "namespace" is just a module object that lives inside
another module, without requiring a separate .py file. It only uses
the "class" statement for pragmatic reasons: there's no other statement
available that will do the job.


> 2/ the fact that classes are more than a namespace is not an argument.
> Almost any object in python is able to do more than what you are
> actually using.

There's one aspect of classes that is a deliberate design feature, but goes
against what I'm after: the fact that the class namespace itself is NOT
part of the method name resolution rules (except during class
construction). Try this:

x = 999

class Example:
    x = 1
    print(x)  # called during class construction
    @classmethod
    def test(cls):
        print(x)


Example.test()



This will print 1, then 999. We quite often get people complaining about
this. I'm not one of them. I want classes to keep the current rules. But it
shows that a class is not the right answer for a module-inside-a-module
object.


> 3/ Classes are used as much as 'is-a' than 'has-a', class instances
> *have* a state usually described by attributes

Instances have state, of course, but the relationship I'm talking about is
instance to class.

class Dog:
    ...

lassie = Dog()

Lassie is a dog, not "Lassie has a dog".

Lassie has a tail, not "Lassie is a tail".


That's why we have IS_instance and HAS_attr builtins.

The expectation is that a class represents a model of a physical kind of
thing, whether that's a Dog or a HTTPServer or a float. If you want a
collection of related functions, classes and variables, put them in a
different kind of namespace, namely a module (if using a separate .py file
is okay) or a Namespace.





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