471,355 Members | 1,693 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,355 software developers and data experts.

Unexpected __metaclass__ method behavior

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
Dec 30 '07 #1
5 1138


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
Dec 30 '07 #2

<an***********@wangnick.dewrote in message
news:22**********************************@i29g2000 prf.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

Dec 30 '07 #3
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
Dec 31 '07 #4
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

Dec 31 '07 #5
an***********@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.
Jan 6 '08 #6

This discussion thread is closed

Replies have been disabled for this discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.