Using a metaclass for this is not the correct approach here. A metaclass modifies the class-creation behavior not the instance creation behavior. You should use the __init__
or the __new__
function to modify instance creation behavior. Wanting to use a metaclass for such things is using a hammer instead of a screwdriver to put a screw in a wall. ;-)
I'd suggest you use __new__
to achieve what you want. From the Python docs:
__new__()
is intended mainly to allow subclasses of immutable types (likeint
,str
, ortuple
) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.
class MetaModel(type):
def __new__(cls, name, bases, attrs):
attrs['_restricted_fields'] = [attrs.get('has_many')]
return type.__new__(cls, name, bases, attrs)
class Model(object):
__metaclass__ = MetaModel
has_many = None
def __new__(cls, *args, **kwargs):
instance = object.__new__(cls, *args, **kwargs)
instance.instance_var = ['spam']
return instance
class SubModel(Model):
has_many = True
def __init__(self):
# No super call here.
self.attr = 'eggs'
s = SubModel()
assert s._restricted_fields == [True] # Added by MetaModel
assert s.instance_var == ['spam'] # Added by Model.__new__
assert s.attr == 'eggs' # Added by __init__
# instance_var is added per instance.
assert SubModel().instance_var is not SubModel().instance_var
The MetaModel
is responsible for creating Model
classes. It adds a _restricted_fields
class variable to any Model
class created by it (the value is a list containing the has_many
class variable).
The Model
class defines a default has_many
class variable. It also modifies the instance creation behavior, it adds an instance_var
attribute to each created instance.
The SubModel
is created by a user of your code. It defines an __init__
function to modify instance creation. Note that it does not call any super-class function, this is not a necessity. The __init__
adds an attr
attribute to each SubClass
instance.