metaclasses and setting __class__
scott at chronis.pobox.com
Thu Jun 3 03:15:49 CEST 1999
On Wed, Jun 02, 1999 at 05:05:01PM -0500, Gordon McMillan wrote:
| scott cotton writes:
| > Last night i was playing with meta classes, and found out
| > that we are not able to assign an instance's __class__
| > attribute to a metaclass instance. was just wondering if
| > this is probably always going to be the case, or if there
| > are any plans to make .__class__ assignable to such beasts.
| It wouldn't do any good. By the time you have an instance, it's too
| late to add metaclass behaviors. All the magic happens at the time
| the "class MyClass(MyMetaClassInstance):" is encountered. At this
| point, MyMetaClassInstance can do all kinds of evil things to the way
| MyClass works.
It seems like all this could happen when __class__ is
assigned to as well, provided the underlying mechanism knew
what to do -- seems like somehow checking interface rather
than type for that assignment would do the trick, but all
that is conjecture - i don't even know if it's possible - or
desirable but it did seem intuitive.
| Assigning to an instance's __class__ will alter the instance's
| behavior and appearance, but not to the same extent that using a
| metaclass will.
challenge: make a metaclass that mucks with it's own class
hierarchy at run time on a per-instance basis. for example:
class A(Meta): pass
class B(A): pass
class C(A): pass
have instances of A become instances of C on instantiation,
and instances of B become instances of C with B replaced for
A in all the __bases__ (and all __bases__ of all __bases__
...) of C. Never mind why it might be considered useful,
or even worse why it could actually make things more clear.
I think I found that metaclasses are the wrong tool for
this, but only after hours of playing with the madness and
nearing a state of raving lunacy. at one point early in the
game, the following:
class MyRealClass(MetaClassInstance): pass
print MyRealClass, type(MyRealClass)
yielded "__getitem__ <'string'>".
I swear - and no I didn't redefine the builtin 'type'.
needless to say, i gave up after a while, and used the
following function instead:
def rebuild(leaf_class, oldbase, newbase):
if leaf_class == oldbase:
class foo: pass
oldbases = leaf_class.__bases__
newbases = 
for base in oldbases:
newbases.append(rebuild(base, oldbase, newbase))
foo.__bases__ = tuple(newbases)
for k, v in leaf_class.__dict__.items():
if k != '__bases__':
foo.__dict__[k] = v
It was used sortof like this:
if self.__class__ != A:
self.__class__ = rebuild(C, A, B)
self.__class__ = C
def extrastuff(self): ...
def other_type_of_extrastuff(self): ...
More information about the Python-list