[this message has also been posted to comp.lang.python] Guido's metaclass hook in Python goes this way: If a base class (let's better call it a 'base object') has a __class__ attribute, this is called to create the new class. >From demo/metaclasses/index.html: class C(B): a = 1 b = 2 Assuming B has a __class__ attribute, this translates into: C = B.__class__('C', (B,), {'a': 1, 'b': 2}) Usually B is an instance of a normal class. So the above code will create an instance of B, call B's __init__ method with 'C', (B,), and {'a': 1, 'b': 2}, and assign the instance of B to the variable C. I've ever since played with this metaclass hook, and always found the problem that B would have to completely simulate the normal python behaviour for classes (modifying of course what you want to change). The problem is that there are a lot of successful and unsucessful attribute lookups, which require a lot of overhead when implemented in Python: So the result is very slow (too slow to be usable in some cases). ------ Python 2.1 allows to attach attributes to function objects, so a new metaclass pattern can be implemented. The idea is to let B be a function having a __class__ attribute (which does _not_ have to be a class, it can again be a function). What is the improvement? Classes, when called, create new instances of themselves, functions can return whatever they want. I've used this pattern to realize the ideas Costas Menico described in an article 'Simulating class' in c.l.p, and James Althoff improved in a followup. The proposal was to create class methods the following way: <--- start of code ---> class Class1MetaClass: # Base for metaclass # Define "class methods" for Class1 def whoami(self): print 'Class1MetaClass.whoami:', self # define Class1 & its "instance methods" class Class1: # Base class def whoami(self): print 'Class1.whoami:', self Class1Meta = Class1MetaClass() # Make & name the singleton metaclass instance Class1 = Class1Meta.Class1 # Make the Class1 name accessible # define subclasses: class Class2MetaClass(Class1MetaClass): [rest of code omitted] # use them: Class1Meta.whoami() # invoke "class method" of base class Class1().whoami() # make an instance & invoke "instance method" i = Class1Meta() # make another instance... i.whoami() # ...invoke "instance method" <--- end of code ---> I find this idea very interesting, but you have to be very verbose: Define a Class1MetaClass, create an instance to use as the metaclass, remeber to use Class1MetaClass (and not! Class2Meta) to define subclasses. ------ I would like (and have implemented) the following way to create class methods. You have to supply the magic MetaMixin object as the first object in the base class list. class SpamClass(MetaMixin): # define "class methods" def whoami(self): print "SpamClass.whoami:", self def create(self, arg1, arg2): # a factory class method return self._instance(arg1, arg2) class _instance_: # define "instance methods" def whoami(self): print "instance.whoami:", self # Subclassing goes this way: class FooClass(MetaMixin, SpamClass): def create(self, arg1, arg2): # override the factory method return self._instance_(arg2, arg1) class _instance_(SpamClass._instance_): # define "instance methods" def blah(self): print "blah:", self self.whoami() # Test them: print SpamClass #prints: <test.SpamClass instance at 007C0D84> SpamClass.whoami() #prints: SpamClass.whoami: <test.SpamClass instance at 007C0D84> s = SpamClass() print s #prints: <__main__.SpamClass_Instance instance at 007C0DAC> s.whoami() #prints: instance.whoami: <__main__.SpamClass_Instance instance at 007C0DAC> ------ Here is finally the code for MetaMixin: <--- start code ---> def MagicObject(name, bases, dict): import types, new l = [] for b in bases: if type(b) == types.FunctionType: # we will see our MetaMixin function here, # but this cannot be used in bases continue if type(b) == types.InstanceType: # l.append(b.__class__) else: l.append(b) bases = tuple(l) # define a new class Class = new.classobj(name, bases, dict) # create an instance of this class # without calling it's __init__ method class_instance = new.instance(Class, {}) # new protocol for initializing try: class_instance.__init_class__ except: pass else: class_instance.__init_class__() Instance = new.classobj("%s_Instance" % name, \ Class._instance_.__bases__, \ Class._instance_.__dict__) Instance.__dict__['__meta__'] = class_instance Class._instance_ = Instance return class_instance def MetaMixin(): pass MetaMixin.__class__ = MagicObject <--- end code ---> Comments? Thomas
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4