Do not define an __init__ method for your classes!
Subclasses of elk.Elk are automatically initialised by the Elk metaclass. Use the __build__ hook for post-construction validation or behaviour.
Elk classes accept keyword arguments matching your attributes (actually, matching their init_arg). You don’t need to worry about setting attributes yourself—simply define a class and you’re ready to start creating objects.
Elk lets you hook into object construction. You can validate an object’s state, do logging or customise construction from parameters which do not match your attributes by defining the __buildargs__ and/or __build__ methods.
If your Elk class defines these methods, the Elk metaclass will arrange for them to be called as part of the object construction process.
The __buildargs__ method is called as a class method before an object is created. It will receive all of the positional and keyword arguments that were passed to the constructor as-is, and must return a dict. The dict will be used to construct the object, so it should contain keys matching your attributes’ names (or init_arg).
One common use for __buildargs__ is to accomodate a non-keyword args calling style. For example, we might want to allow our Person class to be called with a single positional argument, the Tax File Number:
Person(tfn)
A __buildargs__ method can be used to accomodate this calling style:
class Person(elk.Elk):
tfn = elk.ElkAttribute()
@classmethod
def __buildargs__(cls, *args, **kwargs):
if len(args) == 1:
kwargs['tfn'] = args[0]
return kwargs
Note
Without a __buildargs__ method, Elk will raise TypeError if positional arguments are passed.
The __build__ method is called after an object is created. There are several reasons to use a __build__ method. One of the most common is to check that the object state is valid. While we can validate individual attributes through type constraints, we can’t validate the state of a whole object that way.
def __build__(self, **kwargs):
if self.country_of_residence == 'AUS' and not hasattr(self, 'tfn'):
raise RuntimeError('AUS residents must have a Tax File Number')
Another use of a __build__ method could be for logging or tracking object creation:
def __build__(self, **kwargs):
logger.debug('Made a new Person; tfn={}'.format(self.tfn))
The __build__ method is called with the parameters passed to the constructor (after munging by __buildargs__). This gives you a chance to do something with parameters that do not represent object attributes:
def __build__(self, **kwargs):
self.add_friend(User(user_id=kwargs['user_id']))
Note
The default __build__ method raises TypeError if any arguments are received that do not correspond to Elk attributes:
class Person(elk.Elk):
tfn = elk.ElkAttribute()
person = Person(tfn='123456789', name='Bob') # raises TypeError