[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