I
imho
Hi all.
I just send this post as a comment to the third part of Michele
Simionato's article about metaprogramming techniques at:
http://www.ibm.com/developerworks/linux/library/l-pymeta3.html?S_TACT=105AGX03&S_CMP=ART
I found extremely useful the classinitializer "trick". I was thinking
over the caveat not to call a class initializer after the _metaclass_
hook (an exception being raised in that case).
Am I wrong if I state there's a plain solution to this ? I modified the
lines involving "type", replacing it with a custom meta type returned by
a call to frame.f_locals.get("__metaclass__", type), in such a way the
creation of the class involves the right metaclas, even if it was
defined just before the initializer function:
def classinitializer(proc):
# basic idea stolen from zope.interface.advice, P.J. Eby
def newproc(*args, **kw):
frame = sys._getframe(1)
if '__module__' in frame.f_locals and not \
'__module__' in frame.f_code.co_varnames: # we are in a class
thetype = frame.f_locals.get("__metaclass__", type)
def makecls(name, bases, dic):
try:
cls = thetype(name, bases, dic)
except TypeError, e:
if "can't have only classic bases" in str(e):
cls = thetype(name, bases + (object,), dic)
else: # other strange errs, e.g. __slots__ conflicts
raise
proc(cls, *args, **kw)
return cls
frame.f_locals["__metaclass__"] = makecls
else:
proc(*args, **kw)
newproc.__name__ = proc.__name__
newproc.__module__ = proc.__module__
newproc.__doc__ = proc.__doc__
newproc.__dict__ = proc.__dict__
return newproc
This makes the trick work even if a metaclass or another
classinitializer was defined first:
@classinitializer
def enhance(cls, **kw):
for k, v in kw.iteritems():
setattr(cls, k, v)
class M(type):
pass
class A:
__metaclass__ = M
enhance(x=100)
enhance(y=200)
<class '__main__.M'>
What do you think about this solution ?
Diego Novella.
I just send this post as a comment to the third part of Michele
Simionato's article about metaprogramming techniques at:
http://www.ibm.com/developerworks/linux/library/l-pymeta3.html?S_TACT=105AGX03&S_CMP=ART
I found extremely useful the classinitializer "trick". I was thinking
over the caveat not to call a class initializer after the _metaclass_
hook (an exception being raised in that case).
Am I wrong if I state there's a plain solution to this ? I modified the
lines involving "type", replacing it with a custom meta type returned by
a call to frame.f_locals.get("__metaclass__", type), in such a way the
creation of the class involves the right metaclas, even if it was
defined just before the initializer function:
def classinitializer(proc):
# basic idea stolen from zope.interface.advice, P.J. Eby
def newproc(*args, **kw):
frame = sys._getframe(1)
if '__module__' in frame.f_locals and not \
'__module__' in frame.f_code.co_varnames: # we are in a class
thetype = frame.f_locals.get("__metaclass__", type)
def makecls(name, bases, dic):
try:
cls = thetype(name, bases, dic)
except TypeError, e:
if "can't have only classic bases" in str(e):
cls = thetype(name, bases + (object,), dic)
else: # other strange errs, e.g. __slots__ conflicts
raise
proc(cls, *args, **kw)
return cls
frame.f_locals["__metaclass__"] = makecls
else:
proc(*args, **kw)
newproc.__name__ = proc.__name__
newproc.__module__ = proc.__module__
newproc.__doc__ = proc.__doc__
newproc.__dict__ = proc.__dict__
return newproc
This makes the trick work even if a metaclass or another
classinitializer was defined first:
@classinitializer
def enhance(cls, **kw):
for k, v in kw.iteritems():
setattr(cls, k, v)
class M(type):
pass
class A:
__metaclass__ = M
enhance(x=100)
enhance(y=200)
<class '__main__.M'>
What do you think about this solution ?
Diego Novella.