declarative¶
Problem¶
Python does not let derived class have access to their base classes while the derived class is being defined:
>>> class base:
... foo = ('a', 'b')
>>> class derived(base):
... foo += ('c', 'd')
Traceback (most recent call last):
...
NameError: name 'foo' is not defined
Solution¶
The declarative
metaclass solves this:
>>> from flask.ext.dry.api.class_init import declarative
>>> class base(metaclass=declarative):
... foo = ('a', 'b')
>>> class derived(base):
... foo += ('c', 'd')
>>> derived.foo
('a', 'b', 'c', 'd')
Now methods defined on the base class may access these class variables as the declarations that tell them what to do:
>>> class base(metaclass=declarative):
... foo = ('a', 'b') # default values
... def do_foo(self):
... for i in self.foo:
... print("doing", i)
>>> class derived1(base):
... foo += ('c', 'd') # extend default values
>>> class derived2(base):
... foo = ('x', 'y') # replace default values
>>> derived1().do_foo()
doing a
doing b
doing c
doing d
>>> derived2().do_foo()
doing x
doing y
The declarative metaclass makes a deepcopy of each base class attribute referenced by the derived class. This prevents updates made in the derived class from corrupting the base class:
>>> class base(metaclass=declarative):
... foo = ['a', 'b']
>>> class derived(base):
... foo.extend(('c', 'd'))
>>> derived.foo
['a', 'b', 'c', 'd']
>>> base.foo
['a', 'b']