Search code examples
pythonoop

Class variables of same type as the class


Messing around with the typical Point class example when learning Python, I noticed that for some reason I can't have a class level (static variable) of the same type as that of the class. E.g.

class Point:

  ORIGIN = Point() # doesn't work

  def __init__(self, x=0, y=0):
    self.x = x
    self.y = y

while the same works in Java:

class Point {
    private static final Point ORIGIN = new Point(0, 0);
    
    private int x;
    private int y;
    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

The question is: is there any way of achieving the same in Python. Right now I am relying on module level variables and I'm not liking that solution. Also, is there any reason why it can't be done in the body of the class?


Solution

  • You can't create an instance of a class, until that class is actually created, which is after the class body is evaluated (note: it's executed like normal Python code).

    The same goes for your Java example: ClassLoader creates the Point class and then executes the code from static fields.

    A rough equivalent of a class loader in Python is the metaclass, so you could do something like this:

    def class_with_static(name, bases, body):
        static_block = body.pop("__static__", None)
        klass = type(name, bases, body)
        if static_block:
            static_block(klass)
        return klass
    
    class Point(object):
        __metaclass__ = class_with_static
    
        def __static__(cls):
            cls.ORIGIN = cls()
    
        def __init__(self, x=0, y=0):
            self.x = x
            self.y = y
    
    assert isinstance(Point.ORIGIN, Point)
    assert Point.ORIGIN.x == Point.ORIGIN.y == 0
    assert not hasattr(Point, "__static__")
    

    Of course this will have some other consequences, like: all subclasses of Point will have an ORIGIN attribute of their own. So you probably just want to do it like others shown :)