need something like __init__ in classes __classinit__
Kevin Jacobs
jacobs at darwin.epbi.cwru.edu
Fri Mar 8 07:36:51 EST 2002
Jens Gelhaar <cuiod-tec at web.de> wrote:
> class metaclass(type):
> def __new__(cls):
> cls.__classinit__(...)
> class primary(Persistent):
> __metaclass__=metaclass
> def __classinit__(cls):
> << do something ...>
> I get a error message, that I can not inherit from to different
> metaclasses.
I'm not sure my advise will help with ExtensionClasses, since I don't know
enough about how it is implemented. Here is how I think it can be done
without changing the Python core:
class ClassInit(type):
def __new__(cls, name, bases, cls_dict):
# Transform __classinit__ into a static method
class_init = cls_dict.get('__classinit__',None)
if class_init:
cls_dict['__classinit__'] = staticmethod(class_init)
# Call super instead of type.__new__ to allow cooperative metaclasses
return super(ClassInit,cls).__new__(cls, name, bases, cls_dict)
def __init__(self, name, bases, cls_dict):
# Call __classinit__ if it exists and is callable.
# This cannot be done in __new__ since the class may not be completely
# initialized by its metaclasses.
if callable(getattr(self, '__classinit__',None)):
self.__classinit__(self)
class ClassInitObject(object):
__metaclass__ = ClassInit
class Persistent:
pass
class primary(ClassInitObject,Persistent):
def __classinit__(cls):
print "In __classinit__:",cls
def __init__(self):
print "In __init__:",self
p=primary()
The output is then:
In __classinit__: <class '__main__.primary'>
In __init__: <__main__.primary object at 0x812961c>
So the trick is to use multiple inheritance to allow multiple metaclasses.
I have no idea if this will work with an ExtensionClass, but its much more
likely than getting Guido to support __initclass__ in the Python core.
(Anyway, this will certainly work with the ZODB from Zope3.)
I'll add this trick to my growing list of metaclass hacks. If anyone is
interested, I'll post them on my website later today. Here is the current
list of magic metaclasses:
o A metaclass that lazily instantiates slots so that you can write:
class A(object):
__metaclass__ = LazySlotBuilder
__slots__ = ('a')
class B(object):
__metaclass__ = LazySlotBuilder
__slots__ = ('b')
class AB(A,B):
pass
Without the metaclass magic, this would will result in a layout
conflict: TypeError: multiple bases have instance lay-out conflict
o A metaclass that adds constraint checking to attributes and slots. This
can be used to implement type checking in Python:
class A(object):
__metaclass__ = ConstrainedObject
__slots__ = {'a':int,'b':float}
class B(A):
__attrs__ = {'c':str}
foo=B()
foo.a = foo.b = foo.c = 1
assert foo.a == 1
assert foo.b == 1.0
assert foo.c == "1"
assert type(foo.a) == int
assert type(foo.b) == float
assert type(foo.c) == str
foo.a = 'Hello' # Throws a ValueError from trying to run int('Hello')
o A tuple building metaclass that allows access to tuple elements by name
as well as by index. There is also a version that allows access to
elements by name in a case-insensitive manner. These objects are very
useful as a replacement for DB-API row tuples, which is why I call them
Row objects:
ABCRow=RowMetaClass(['a','b','c'])
r=ABCRow( (1,2,3) )
assert r['a']==r[0]==r.a==1
assert r['b']==r[1]==r.b==2
assert r['c']==r[2]==r.c==3
ABCRow=InsensitiveRowMetaClass(['a','b','c'])
r=ABCRow( (1,2,3) )
assert r['a']==r['A']==r[0]==r.A==r.a==1
assert r['b']==r['B']==r[1]==r.B==r.b==2
assert r['c']==r['C']==r[2]==r.C==r.c==3
o The above ClassInit metaclass.
Regards,
-Kevin
--
Kevin Jacobs
The OPAL Group - Enterprise Systems Architect
Voice: (216) 986-0710 x 19 E-mail: jacobs at theopalgroup.com
Fax: (216) 986-0714 WWW: http://www.theopalgroup.com
More information about the Python-list
mailing list