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