Django uses python metaclasses to achieve this.
Much like a regular class
is a template from which to create objects, a metaclass is is the template from which to create classes.
When you declare a regular class
:
class A(object):
pass
The default metaclass (type
) is what is responsible for creating A
. It does so by processing the things you have defined in A
in order to create a the object that actually represents A
.
In Django, the developers changed the metaclass of models.Model
to their own custom metaclass. In doing so, they get to control the creation of any class that derives from models.Model
, and can do the "magic" that you refer to.
Django uses similar magic to do lots of other things, too!
For example, I can do the following to replicate what you are seeing Django do:
class MetaClass(type):
@staticmethod
def _create_getter(attr):
def _getter(self):
return getattr(self, attr)
return _getter
def __init__(self, name, bases, attrs):
super(MetaClass, self).__init__(name, bases, attrs)
for attr in attrs:
if not attr.startswith('_'):
setattr(self, 'get_%s' % attr, MetaClass._create_getter(attr))
class Base(object):
__metaclass__ = MetaClass
Now, any class that derives from Base
will automatically acquire getter methods for each of it public attributes (those not starting with an _
).
Here's is being used:
class A(Base):
x = 2
a = A()
print a.get_x()