[Types-sig] Re: Meta-classes discussion starter

Just van Rossum just@letterror.com
Wed, 2 Dec 1998 14:00:02 +0100


>> +                       PyDict_DelItemString(methods, "__class__");

At 10:31 AM +0100 12/2/98, M.-A. Lemburg wrote:
>I like the patch... but why do you delete the __class__ attribute ?

I must admit that the one aspect of the patch I am not quite confident about...

>To prevent endless recursion in some weird cases ?

No, merely from this view: while playing with the mechanism, I found myself
constantly deleting __class__ from the dict in Python. I could not find any
reason why I would ever need the __class__ entry. It's a little like this:

def somefunction(dict):
    pass

mydict = {"foo": somefunction}

if mydict.has_key("foo"):
    func = mydict["foo"]
    func(mydict)

It just seemed silly to have __class__ still around, especially since I
cannot use it as a real attribute anyway: in instance can only have a Real
Class object as __class__ attribute. So in my experiments I used __klass__
to bind my fake class object to.

[ *** warning: the author is drifting *** ed. ]

*Maybe* it would be even cooler (in today's Python, maybe not 2.0) to use
__metaclass__ (or __turtle__, *whatever*) as the secret word, and have a
second GuidoHook that triggers with that same name *before* it checks for
__class__. Or for my part get rid of the __class__ check altogether. That
way it we could have even more control over classes. Right now, say I
define a little metaclass like this:

class MyMetaClass:
    def __init__(self, name, bases, namesspace):
        ... etc.

Then I can create a "normal" class like this:

class MyClass:
    __class__ = MyMetaClass

This invoked my hook. Then I subclass:

class MySecondClass(MyClass):
    pass

This invokes Guido's hook, which will call MyMetaClass since that's
MyClass's *real* __class__ attribute, so MySecondClass will automatically
be an instance of MyMetaClass. Fine. Almost too perfect.

The caveat is this: Guido's Hook *requires* that __class__ is a real class
(well, no, sure it's not really the hook that forces this, but it's a side
effect of choosing the name __class__ as secret trigger) which means the
constructor of a class is *always* some __init__ func of a metaclass. Which
means we can't emulate the current Python object model in full since we
can't trap access to an "__init__" attr: it will always be found before any
__getattr__ func can get triggered... It really means that I cannot by
definition make this work correctly:

class MyClass:
    __class__ = MyMetaClass
    def __init__(self, a):
        self.a = a

class MySecondClass(MyClass):
    def __init__(self):
        MyClass.__init__(self, 100)

The last line can't work because
- MyClass is in instance of MyMetaClass
- MyClass.__init__ will be found in MyMetaClass *before* it can trigger any
__getattr__ that could look it up inside MyClass.

It's not easy, but it could be made work with Today's Python had "we" not
chosen __class__ as the magic attribute for metahooks...


Just