Slight metaclass confusion

Ben Young ben.young at transversal.com
Wed Sep 10 05:56:46 EDT 2003


On Tue, 9 Sep 2003, David Mertz wrote:

> ben at transversal.com (ben at transversal.com) wrote previously:
> |"Metaclass Programming In Python, Parts 1 and 2"
> |I get the fact that the instance of a metaclass is a class, but in
> |this case I fail to see why the following does'nt work:
>
> Read part 2 again.  It takes a while to sink in.
>
> Your problem is that you aren't considering the MRO of Class:
>
>   >>> class Meta(type):
>   ...     def __str__(cls):     # Use 'return', not 'print'
>   ...             return "I am " + repr(cls)
>   ...     def foo(cls):
>   ...             return "I am " + repr(cls)
>   ...
>   >>> Class = Meta("Fish", (), {})
>   >>> Class.foo()
>   "I am <class '__main__.Fish'>"
>
> Class is an instance of Meta, just like you expect.  Calling the .foo()
> method shows this.  But when you call a method, the method name is
> checked in the -method resolution order- (before the metaclass is
> checked):
>
>   >>> Class.mro()
>   [<class '__main__.Fish'>, <type 'object'>]
>
> Fish doesn't define a method .__str__(), so Python looks in Fish's
> parent, object.  Well, object -does- define, .__str__(), so your call
> resolves to:
>
>   >>> object.__str__()
>   Traceback (most recent call last):
>     File "<stdin>", line 1, in ?
>   TypeError: descriptor '__str__' of 'object' object needs an argument
>
> Of course, since object doesn't define a .foo(), resolution proceeds to
> the metaclass.  If you want to get Class' metaclass method, you can let
> Python do the magic for you:
>
>   >>> str(Class)
>   "I am <class '__main__.Fish'>"
>
> Or if you want to be really explicit:
>
>   >>> Class.__class__.__str__(Class)
>   "I am <class '__main__.Fish'>"
>
> Yours, David...

Right I think i'm getting there now. Thanks to all those who replied!

I see now that *instances* if classes must always look in their class dist
because they _don't have an mro_, whereas classes do and this is always
looked at first, causing the unbound method error.

Does this mean function calls are done something like this (untested code)

mro = getattr(obj, "mro", None)
if mro:
	for i in mro:
		func = getattr(i, "function")
		if func:
			return func(*args, **kw)

#Fall through
return getattr(type(obj), "function")(obj, *args, **kw)

Ben
---

>
> --
>     _/_/_/ THIS MESSAGE WAS BROUGHT TO YOU BY: Postmodern Enterprises _/_/_/
>    _/_/    ~~~~~~~~~~~~~~~~~~~~[mertz at gnosis.cx]~~~~~~~~~~~~~~~~~~~~~  _/_/
>   _/_/  The opinions expressed here must be those of my employer...   _/_/
>  _/_/_/_/_/_/_/_/_/_/ Surely you don't think that *I* believe them!  _/_/
>
>
>




More information about the Python-list mailing list