some simple functions for dynamically adding methods, properties,and classmethods to classes at runtime
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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | #!/usr/bin/env python
#-----------------------------------------------------------------------------
# Copyright 2003 by Bud P. Bruegger, Sistema, Italy
# mailto:bud@sistema.it
# http://www.sistema.it
#-----------------------------------------------------------------------------
# dynClass -- Dynamic Classes
# ---------------------------
#
# some simple functions for dynamically adding methods, properties
# and classmethods to classes at runtime.
#
#-----------------------------------------------------------------------------
# see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732
# and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81982
# and http://www.python.org/2.2/descrintro.html#property
import new
import sys
def addMethod(classInstance, func, methName=None):
"""adds function as a new method to an existing class
function should have self as first argument
"""
meth = new.instancemethod(func, None, classInstance)
name = methName or func.__name__
setattr(classInstance, name, meth)
return name
def addProperty(classInstance, attrName, fget, fset, fdel=None, \
fdoc="this is magic"):
"""adds a property to an existing class """
prop = property(fget, fset, fdel, fdoc)
setattr(classInstance, attrName, prop)
def addClassMethod(classInstance, func, methName=None):
"""adds function as a new class method to an existing class.
function should have self as first argument
"""
name = methName or func.__name__
setattr(classInstance, name, classmethod(func))
def classFromName(className):
"returns the class instance object"
return getattr(sys.modules['__main__'], className)
#========== example usage ====================================================
if __name__ == "__main__":
pass
#-- testing addMethod ------------------
def func1(self):
"some test function"
return "Name is %s" % self._name
def func2(self, comment=''):
"some test function"
return "Age is %s %s" % (self._age, comment)
class Example(object):
"some example class"
def __init__(self, name, age):
self._name = name
self._age = age
sarah = Example('Sarah', 5)
josh = Example('Josh', 2)
addMethod(Example, func1, 'getName')
addMethod(Example, func2, 'getAge')
lucia = Example('Lucia', 20)
# Does it work as expected?
print sarah.getName()
print sarah.getAge('at least soon')
print josh.getName()
print josh.getAge('and wild')
print lucia.getName()
print lucia.getAge('some time ago')
print "\n-----------------------\n"
#-- testing properties ------------------
def getAltName(self):
return "*" + self._name + "*"
def setAltName(self, val):
self._name = val[1:-1]
addProperty(Example, 'altName', getAltName, setAltName)
print sarah.altName
sarah.altName="*NEW-SARAH*"
print sarah.altName
print sarah.getName()
bud = Example('Bud', 42)
print bud.altName
bud.altName="*The king of beers*"
print bud.altName
print bud.getName()
print "\n-----------------------\n"
#-- testing classFromName -----------
print "The class named 'Example' is %s" % classFromName('Example')
class EEE(object):
pass
print "The class named 'EEE' is %s" % classFromName('EEE')
print "\n-----------------------\n"
#-- testing addClassMethod -----------------------
class C(object):
pass
def func(cls):
return "<<%s>>" % cls.__name__
addClassMethod(C, func, 'className')
print "the class name is: ", C.className()
|
It is sometimes useful to modify classes at runtime, for example to implement some weakly coupled persistance mechanism for user-defined classes. While some recipes already address related issues (see links in code), this submission attempts to consolidate them in a single reusable module.