Hello Carlos,
I'm not a metaclass expert, but I think I can share a few useful tips
with you. I've been studying metaclasses lately, and I've fallen on
some traps that seem to be common. I apologize if my tone sound
pretentious at times -- my intention is probably better than my words.
Your description is really interesting and informative,
as usual.
[...]
... for i in range(10):
... def newmethod(self,i=i):
... print "I'm method #%d" % i
... newname = "method%d" % i
... locals()[newname] = newmethod
... I'm method #1
Although it doesn't involve metaclasses at all, it shows how dynamic
the class creation process is, and how much control one can have with
it. There are two worthy comments to make:
1) the locals() dict is the key at this step of class creation. The
local dict is one of the parameters passed to the metaclass. If you
fill the locals() with values -- either manually, as in the example
above, or by assigning values to local vars -- all the values will be
part of the class definition.
As an interesting side effect, the class above will have
'newname', 'newmethod', and 'i' attributes, besides 'method0-9'.
2) the signature of "def newmethod(self,i=i)" shows another
interesting side effect. The value if <i> (defined in the for loop) is
passed as a keyword paramenter, and is evaluated whenever the 'def'
statement is found. Because it changes, the def is re-run at every
loop. In the lack of this hack, the def would run only at the first
time, and all methods would in fact be the same.
That's not true. The def statement is rerun every loop, no matter
what parameters are used. One can check that by issuing:
print MyClass.method0.im_func
print MyClass.method1.im_func
Of course, in your example, not using the 'i=i' trick would be a
problem, since the 'i' variable is lost, and inside the method a
global is looked for, creating an error.