This is a class adapted from one that performs a similar task in the PyML libraries by Asa Ben-Hur et al (see: http://pyml.sourceforge.net/).
The intention is to speed up development time, by allowing managed attribute names (and their default values) to be specified in a dictionary belonging to each class (here called classinitials). This avoids rewriting the standard initialisation procedure many times over.
Subclasses inherit all superclasses' managed attributes, including the defaults unless overridden. This is found in the property initials. The copy constructor copies all managed attributes.
Finally, any named argument to the __init__ function, whose name appears in the managed attributes dictionary, overrides the class default.
I welcome any comments, criticism or suggested improvements.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | ### The suggested superclass ###
class AutoInit (object) :
"""
Each class that inherits from AutoInit (directly or indirectly) can
specify all standard attributes and their initials in dictionary called
classinitials.
Important: if used, it is recommended to specify an attribute with default value None (for copy constructor)
"""
def get_initials(self):
# list of classes in inheritance list (superclasses first)
# care should be taken with multiple inheritance,
# if unsure of class heirachy then overide all initials in originating class.
clss = list(self.__class__.__mro__)
clss.reverse()
initials = {}
for cls in clss:
if hasattr(cls,'classinitials'):
initials.update(getattr(cls,'classinitials'))
return initials
initials = property( get_initials )
def __init__(self, *args, **kwargs) :
# check that the class-attribute 'classinitials' exists
if not hasattr(self, 'initials') : return
# if arg is same type as this then copy construct
if len(args) > 0 and self.__class__ == args[0].__class__ :
arg = args[0] # first element in args is now object to copy
# for each attribute in classinitials copy from arg.attribute to this.attribute
for attribute in self.initials :
setattr(self, attribute, getattr(arg, attribute))
# where args is empty or first arg is not of same class then ignore.
# insted copy all present managed attributes from kwargs dictionary
# where not present get default from initials dictionary.
else :
for attribute in self.initials :
if attribute in kwargs :
setattr(self, attribute, kwargs[attribute])
else :
setattr(self, attribute, self.initials[attribute])
def get_managed_dict(self):
"""
Returns a dictionary of objects attributes, where attribute names are given in self.initials
"""
return dict([ (k,getattr(self,k)) for k in self.initials ])
def __str__(self):
return str(self.get_managed_dict())
### example subclasses ###
class A(AutoInit):
classinitials = { 'attr1' : 'set from A' }
def __init__(self,*args,**kwargs):
AutoInit.__init__(self,*args,**kwargs)
class B(A):
classinitials = { 'attr2' : 'set from B' }
def __init__(self,*args,**kwargs):
A.__init__(self,*args,**kwargs)
class C(B):
classinitials = { 'attr1' : 'set from C',
'attr3' : 'set from C' }
def __init__(self,*args,**kwargs):
B.__init__(self,*args,**kwargs)
### example usage ###
def test():
a = A()
b = B()
c1 = C()
c2 = C(attr1='set by constructor argument to c2')
c3 = C(c2)
print "Initialised objects:"
print "a:",a
print "b:",b
print "c1:",c1
print "c2:",c2
print "c3:",c3
print
## objects can then be used normally ##
c1.attr1 = 'set externally'
print "After manual set operation:"
print "c1:",c1
### run from command line if you like ###
if __name__ == '__main__':
test()
|
Expected output: