metaclasses and setting __class__
scott cotton
scott at chronis.pobox.com
Wed Jun 2 21:15:49 EDT 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:
return newbase
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
return foo
It was used sortof like this:
class A:
def __init__(self):
if self.__class__ != A:
self.__class__ = rebuild(C, A, B)
else:
self.__class__ = C
class B(A):
def extrastuff(self): ...
class C(A):
def other_type_of_extrastuff(self): ...
scott
More information about the Python-list
mailing list