Unexpected __metaclass__ method behavior

Discussion in 'Python' started by anne.nospam01@wangnick.de, Dec 30, 2007.

  1. Guest

    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, 2007
    #1
    1. Advertising

  2. 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
     
    Michele Simionato, Dec 30, 2007
    #2
    1. Advertising

  3. Terry Reedy Guest

    <> wrote in message
    news:...
    | 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
     
    Terry Reedy, Dec 30, 2007
    #3
  4. Guest

    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, 2007
    #4
  5. On Dec 31, 12:06 pm, 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
     
    Arnaud Delobelle, Dec 31, 2007
    #5
  6. 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.
     
    Bruno Desthuilliers, Jan 6, 2008
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David M. Wilson

    Understanding and working with __metaclass__

    David M. Wilson, Dec 8, 2003, in forum: Python
    Replies:
    4
    Views:
    1,492
    Michele Simionato
    Dec 9, 2003
  2. Roman Yakovenko

    __slots__, setattr, __metaclass__

    Roman Yakovenko, Jan 12, 2004, in forum: Python
    Replies:
    1
    Views:
    303
    Michele Simionato
    Jan 12, 2004
  3. H Jansen
    Replies:
    3
    Views:
    498
    Steven Bethard
    Jul 28, 2004
  4. Paul Morrow
    Replies:
    10
    Views:
    590
    Tor Iver Wilhelmsen
    Aug 22, 2004
  5. Joel Hedlund

    Is this a good use of __metaclass__?

    Joel Hedlund, May 5, 2006, in forum: Python
    Replies:
    9
    Views:
    325
    Michele Simionato
    May 9, 2006
Loading...

Share This Page