[Python-Dev] New metaclass pattern (Was Re: Simulating Class (was Re: Does Python have Class methods)) (original) (raw)
Thomas Heller thomas.heller@ion-tof.com
Wed, 23 May 2001 19:28:07 +0200
- Previous message: [Python-Dev] Re: Simulating Class (was Re: Does Python have Class methods)
- Next message: [Python-Dev] New metaclass pattern (Was Re: Simulating Class (was Re: Does Python have Class methods))
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
[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
- Previous message: [Python-Dev] Re: Simulating Class (was Re: Does Python have Class methods)
- Next message: [Python-Dev] New metaclass pattern (Was Re: Simulating Class (was Re: Does Python have Class methods))
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]