Re: Choosing a Metaclass?

2008-02-21 Thread Steve Holden
Jeff McNeil wrote:
> Hi list,
> 
> Hopefully a quick metaclass question. In the following example, MyMeta 
> is a metaclass that does not inherit directly from type:
> 
> #!/usr/bin/python
> 
> class MyMeta(object):
> def __new__(cls, name, bases, vars):
> print "MyMeta.__new__ called for %s" % name
> return type(name, bases, vars)
> 
> class MetaWrapper(object):
> __metaclass__ = MyMeta
> 
> class M(MetaWrapper):
> pass
> 
> [EMAIL PROTECTED] ~]$ python t.py
> MyMeta.__new__ called for MetaWrapper
> [EMAIL PROTECTED] ~]$
> 
> When I run that script, it's apparent that although M inherits from 
> MetaWrapper, it does not use MyMeta as it's metaclass.  However, if I 
> change MyMeta to be a subclass of builtin type, it works as I would expect:
> 
> [EMAIL PROTECTED] ~]$ cat t.py
> #!/usr/bin/python
> 
> class MyMeta(type):
> def __new__(cls, name, bases, vars):
> print "MyMeta.__new__ called for %s" % name
> return super(MyMeta, cls).__new__(cls, name, bases, vars)
> 
> class MetaWrapper(object):
> __metaclass__ = MyMeta
> 
> class M(MetaWrapper):
> pass
> 
> [EMAIL PROTECTED] ~]$ python t.py
> MyMeta.__new__ called for MetaWrapper
> MyMeta.__new__ called for M
> [EMAIL PROTECTED] ~]$
> 
> How exactly does Python choose which MC it will use when building a 
> class?  It doesn't seem to me that the parent class of MyMeta should 
> matter in this case?
> 
When you create a subclass M of MetaWrapper in your first example, 
MetaWrapper is a subclass of object that has no metaclass of its own, 
and therefore it resolves __new__() from object:

 >>> MetaWrapper.__bases__
(,)
 >>> MetaWrapper.__metaclass__

 >>> dir(MyMeta)
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', 
'__hash__', '__init__', '__module__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__']
 >>> MetaWrapper.__new__


In your second example MyMeta is a subclass of type, and therefore it 
resolves type's __new__(), which is what takes the special actions you 
observe when a subclass is defined:

 >>> MetaWrapper.__bases__
(,)
 >>> MetaWrapper.__metaclass__

 >>> dir(MyMeta)
['__base__', '__bases__', '__basicsize__', '__call__', '__class__', 
'__cmp__', '__delattr__', '__dict__', '__dictoffset__', '__doc__', 
'__flags__', '__getattribute__', '__hash__', '__init__', '__itemsize__', 
'__module__', '__mro__', '__name__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__str__', '__subclasses__', 
'__weakrefoffset__', 'mro']
 >>> MetaWrapper.__new__

 >>>

Hope this helps. Remember that when there is no __metaclass__ defined in 
a class's body (and the module namespace has no default __metaclass__) 
the class's metaclass is the type of the class's first base class.

regards
  Steve
-- 
Steve Holden+1 571 484 6266   +1 800 494 3119
Holden Web LLC  http://www.holdenweb.com/

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Choosing a Metaclass?

2008-02-21 Thread Jeff McNeil
Never mind, I've figured it out.  The build_class function looks at the
'__class__' attribute of the first base class if there's no explicit
__metaclass__ attribute. By calling type directly, the __class__ attribute
as returned by MyMeta is, in fact, type.

Should have just looked at the source to begin with.

On 2/21/08, Jeff McNeil <[EMAIL PROTECTED]> wrote:
>
> Hi list,
>
> Hopefully a quick metaclass question. In the following example, MyMeta is
> a metaclass that does not inherit directly from type:
>
> #!/usr/bin/python
>
> class MyMeta(object):
> def __new__(cls, name, bases, vars):
> print "MyMeta.__new__ called for %s" % name
> return type(name, bases, vars)
>
> class MetaWrapper(object):
> __metaclass__ = MyMeta
>
> class M(MetaWrapper):
> pass
>
> [EMAIL PROTECTED] ~]$ python t.py
> MyMeta.__new__ called for MetaWrapper
> [EMAIL PROTECTED] ~]$
>
> When I run that script, it's apparent that although M inherits from
> MetaWrapper, it does not use MyMeta as it's metaclass.  However, if I change
> MyMeta to be a subclass of builtin type, it works as I would expect:
>
> [EMAIL PROTECTED] ~]$ cat t.py
> #!/usr/bin/python
>
> class MyMeta(type):
> def __new__(cls, name, bases, vars):
> print "MyMeta.__new__ called for %s" % name
> return super(MyMeta, cls).__new__(cls, name, bases, vars)
>
> class MetaWrapper(object):
> __metaclass__ = MyMeta
>
> class M(MetaWrapper):
> pass
>
> [EMAIL PROTECTED] ~]$ python t.py
> MyMeta.__new__ called for MetaWrapper
> MyMeta.__new__ called for M
> [EMAIL PROTECTED] ~]$
>
> How exactly does Python choose which MC it will use when building a
> class?  It doesn't seem to me that the parent class of MyMeta should matter
> in this case?
>
> Thanks!
>
> Jeff
>
>
-- 
http://mail.python.org/mailman/listinfo/python-list

Choosing a Metaclass?

2008-02-21 Thread Jeff McNeil
Hi list,

Hopefully a quick metaclass question. In the following example, MyMeta is a
metaclass that does not inherit directly from type:

#!/usr/bin/python

class MyMeta(object):
def __new__(cls, name, bases, vars):
print "MyMeta.__new__ called for %s" % name
return type(name, bases, vars)

class MetaWrapper(object):
__metaclass__ = MyMeta

class M(MetaWrapper):
pass

[EMAIL PROTECTED] ~]$ python t.py
MyMeta.__new__ called for MetaWrapper
[EMAIL PROTECTED] ~]$

When I run that script, it's apparent that although M inherits from
MetaWrapper, it does not use MyMeta as it's metaclass.  However, if I change
MyMeta to be a subclass of builtin type, it works as I would expect:

[EMAIL PROTECTED] ~]$ cat t.py
#!/usr/bin/python

class MyMeta(type):
def __new__(cls, name, bases, vars):
print "MyMeta.__new__ called for %s" % name
return super(MyMeta, cls).__new__(cls, name, bases, vars)

class MetaWrapper(object):
__metaclass__ = MyMeta

class M(MetaWrapper):
pass

[EMAIL PROTECTED] ~]$ python t.py
MyMeta.__new__ called for MetaWrapper
MyMeta.__new__ called for M
[EMAIL PROTECTED] ~]$

How exactly does Python choose which MC it will use when building a class?
It doesn't seem to me that the parent class of MyMeta should matter in this
case?

Thanks!

Jeff
-- 
http://mail.python.org/mailman/listinfo/python-list