[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Unexpected __metaclass__ method behavior

anne.nospam01

12/30/2007 12:00:00 PM

Dear fellow Pythonians,

I just stumbled upon the following unexpected behavior:

class TestType(type):
def Foo(self): return 'TestType Foo'
class Test(object):
__metaclass__ = TestType
def Foo(self): return 'Test Foo'
t = Test()
print t.Foo()
print Test.Foo()

This will produce:
Test Foo
Traceback (most recent call last):
File "test.py", line 8, in <module>
print Test.Foo()
TypeError: unbound method Foo() must be called with Test instance as
first argument (got nothing instead)

I can imagine why this is happening, and that there is no easy
solution, but it is not what I was expecting.

Anybody willing to explain the details of what's exactly going on
during the method lookup of Test.Foo?

Kind regards,
Sebastian
5 Answers

Michele Simionato

12/30/2007 12:09:00 PM

0



anne.nospa...@wangnick.de wrote:
> Dear fellow Pythonians,
>
> I just stumbled upon the following unexpected behavior:
>
> class TestType(type):
> def Foo(self): return 'TestType Foo'
> class Test(object):
> __metaclass__ = TestType
> def Foo(self): return 'Test Foo'
> t = Test()
> print t.Foo()
> print Test.Foo()
>
> This will produce:
> Test Foo
> Traceback (most recent call last):
> File "test.py", line 8, in <module>
> print Test.Foo()
> TypeError: unbound method Foo() must be called with Test instance as
> first argument (got nothing instead)
>
> I can imagine why this is happening, and that there is no easy
> solution, but it is not what I was expecting.
>
> Anybody willing to explain the details of what's exactly going on
> during the method lookup of Test.Foo?

The regular method is checked for *before* the metaclass method.
You must use

type(Test).Foo(Test)

to call the method. It is clear that it must be that way: when you do
(for instance)
SomeClass.__init__ you do not expect to have type.__init__(SomeClass)
called.
Notice that *all* classes have a metaclass, by default "type" for new-
style
classes and "ClassType" for old-style ones.

Michele Simionato

Terry Reedy

12/30/2007 11:03:00 PM

0


<anne.nospam01@wangnick.de> wrote in message
news:2273796e-87c6-4100-a5b5-1c6afa32a276@i29g2000prf.googlegroups.com...
| Dear fellow Pythonians,
|
| I just stumbled upon the following unexpected behavior:
|
| class TestType(type):
| def Foo(self): return 'TestType Foo'
| class Test(object):
| __metaclass__ = TestType
| def Foo(self): return 'Test Foo'
| t = Test()
| print t.Foo()
| print Test.Foo()
|
| This will produce:
| Test Foo
| Traceback (most recent call last):
| File "test.py", line 8, in <module>
| print Test.Foo()
| TypeError: unbound method Foo() must be called with Test instance as
| first argument (got nothing instead)
|
| I can imagine why this is happening, and that there is no easy
| solution, but it is not what I was expecting.

Regardless of which Foo you expect to be called, both require an instance
argument to be bound to the paramenter 'self'.

print Test.Foo(t) # will print same as t.Foo()

tjr



anne.nospam01

12/31/2007 12:07:00 PM

0

Well, you see, I have some database functions that deal with "things"
which are either classes or instances thereof. I though polymorphism
would be a nice way to handle them identically, like:

def do(thing): thing.Foo()
do(t)
do(Test)

But never mind, I now understand that Test.__dict__ can contain only
one entry for 'Foo', and that this must be matched.

Kind regards,
Sebastian

Arnaud Delobelle

12/31/2007 6:33:00 PM

0

On Dec 31, 12:06 pm, anne.nospa...@wangnick.de wrote:
> Well, you see, I have some database functions that deal with "things"
> which are either classes or instances thereof. I though polymorphism
> would be a nice way to handle them identically, like:
>
> def do(thing): thing.Foo()
> do(t)
> do(Test)
>
> But never mind, I now understand that Test.__dict__ can contain only
> one entry for 'Foo', and that this must be matched.
>
> Kind regards,
> Sebastian

Of course you can do this. The trick is *not* to use metaclasses!

class Bar(object):
def foo(self): return 'instance foo'
@classmethod
def classfoo(cls): return 'class foo'

def do(x):
if isinstance(x, type):
return x.classfoo()
else:
return x.foo()

Then:

>>> bar = Bar()
>>> do(bar)
'instance foo'
>>> do(Bar)
'class foo'

HTH

--
Arnaud



Bruno Desthuilliers

1/6/2008 6:44:00 PM

0

anne.nospam01@wangnick.de a écrit :
> Well, you see, I have some database functions that deal with "things"
> which are either classes or instances thereof. I though polymorphism
> would be a nice way to handle them identically, like:
>
> def do(thing): thing.Foo()
> do(t)
> do(Test)
>
> But never mind, I now understand that Test.__dict__ can contain only
> one entry for 'Foo', and that this must be matched.

You may want to have a look at FormEncode's "declarative" API, with
particular attention to the 'classinstancemethod' stuff.