Two implementations for extending an exsisting class using metaclasses
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
def get_obj(name): return eval(name) class ExtendReplace(type): def __new__(self, name, bases, dict): prevclass = get_obj(name) del dict['__module__'] del dict['__metaclass__'] dict.update(prevclass.__dict__) ret = type.__new__(self, name, prevclass.__bases__, dict) return ret class ExtendInplace(type): def __new__(self, name, bases, dict): prevclass = get_obj(name) del dict['__module__'] del dict['__metaclass__'] # We can't use prevclass.__dict__.update since __dict__ # isn't a real dict for k,v in dict.iteritems(): setattr(prevclass, k, v) return prevclass class Test: __metaclass__=ExtendReplace def test_extend1(self): return 'Test Extend 1' ext1 = Test() assert ext1.test()=='Test' assert ext1.test_extend1()=='Test Extend 1' class Test: __metaclass__=ExtendInplace def test_extend2(self): return 'Test Extend 2' ext2 = Test() assert ext2.test()=='Test' assert ext2.test_extend1()=='Test Extend 1' assert ext2.test_extend2()=='Test Extend 2'
This is a great way to split class definitions or to extend an exsisting class from a different module. I didn't approach this problem for the sake of using it, but just for the sake of seeing if I could have python do it. Well, it did, and very nicely. If you have a good use for this please say so. :)
The two different implementations approach the problem from different angles. The first creates a new class based on the previous class. I believe the previous class should be garbage collected but I am not sure. It has the benefit of not modifying the original class and therefore wont ruin already exsisting instances of the class. This behavior is more of extending a class but not for splitting a definition.
The second just adds the new definitions to the exsisting previous class. Any instance of the class before the extension will be modified to include the changes! This approach has the benefit of not creating more types, and fits much better into splitting up a class definition up.
Example of usage:
class 3dPerson(EnviormentObject): def __init__(self): ...
name = property(....) ....
class 3dPerson: # Notice I do not repeat the base class __metaclass__ = ExtendInplace
def draw(surface): .... ....
class 3dPerson: __metaclass__ = ExtendInplace
def find_optimal_path(destination): ... ...