[Tutor] Problem with calling class methods stored in a list

Tobias M. tm at tobix.eu
Thu Jan 10 13:53:29 CET 2013


Steven D'Aprano wrote:
> To answer your direct question, all you need to do is manually imitate 
> what
> Python does when you call a descriptor (see below):
>
>
> py> MyClass.method_list[0].__get__(MyClass, None)()
> Hello World
>
>
> So, inside the foo() method, do this:
>
>     @classmethod
>     def foo(cls):
>         cls.method_list[0].__get__(cls, None)()
>
>
> and it should work.
>
> "What the hell is a descriptor?" I hear you ask. Don't worry about them,
> they are an advanced part of Python, used to implement methods (regular,
> class and static) and properties. If you care, you can read this:
>
> http://docs.python.org/2/howto/descriptor.html
>
> but you may find it heavy going. (I know I did the first five times I
> read it.)
>
> Here's another solution: use a regular function object instead of a
> method. This relies on an unusual, but deliberate, quirk of the way 
> Python
> implements methods: they are actually regular functions inside the class
> body when the class is created, and don't get turned into methods 
> until you
> do a lookup like "self.spam" or "cls.ham".
>
>
> class MyClass(object):
>     @classmethod
>     def foo(cls):
>         # Note that you manually provide the class argument.
>         cls.method_list[0](cls)
>
>     def bar(cls):
>         print("Hello World")
>
>     # At this time, bar is still a regular function object, not a
>     # method of any sort.
>     method_list = [bar]
>     del bar  # just to avoid any confusion
>
>
> By *not* turning bar into a class method, it remains an ordinary
> function object. You then store the function object inside the list,
> and when you access it via method_list[0] Python gives you the regular
> function, not a method. Since it is a regular function, it is callable,
> but you have to manually provide the cls argument.
>

Thank you for this great answer!
I like the first approach (using __get__()). I tried it out but got 
problem when bar operates on a class variable of MyClass:

class MyClass(object):

     x = "Hello World"

     @classmethod
     def foo(cls):
         cls.method_list[0].__get__(cls, None)()

     @classmethod
     def bar(cls):
         print(cls.x)

     method_list = [bar]


I get:
File "test.py", line 17, in bar
     print(cls.x)
AttributeError: type object 'type' has no attribute 'x'

When using Peter Otten's solution bar is able to access cls.x.




More information about the Tutor mailing list