How to store functions as class variables in python?

时间:2019-01-07 12:57:27

标签: python python-3.x

I am writing a framework, and I want my base class to use different functions for renaming in the child classes. I figured the best way would be to use a class attribute, like in case of A, but I got TypeErrors when running it like in rename_columns(). However it worked with implementation like B

import pandas as pd

class A:
    my_func_mask = str.lower
    foo = 'bar'

    def rename_columns(self, data):
        return data.rename(columns=self.my_func_mask)

class B(A):

    def rename_columns(self, data):
        return data.rename(columns=self.__class__.my_func_mask)

So I experimented with the above a bit, and I get the following:

a = A()
a.foo # Works fine, gives back 'bar'
a.__class__.my_func_mask # Works as expected `a.__class__.my_func_mask is str.lower` is true
a.my_func_mask # throws TypeError: descriptor 'lower' for 'str' objects doesn't apply to 'A' object

My questions would be why can I use regular typed (int, str, etc.) values as class attributes and access them on the instance as well, while I cannot do that for functions? What happens during the attribute lookup in these cases? What is the difference in the attribute resolution process? Actually both foo and my_func_mask is in __class__.__dict__ so I am a bit puzzled. Thanks for the clarifications!

3 个答案:

答案 0 :(得分:9)

您将在类中存储一个未绑定的内置方法,这意味着它是descriptor object。然后,当您尝试在self上访问该描述符时,将应用描述符绑定,但是调用__get__ method来完成绑定时会告诉您它不能绑定到您的自定义类实例,因为该方法只能工作在str个实例上。这是大多数内置类型方法的严格限制。

您需要以其他方式存储它;将其放在另一个容器(例如列表或字典)中,将避免绑定。或者,您也可以将其包装在staticmethod descriptor中,以绑定 并返回原件。另一个选择是不将其存储为类属性,而仅在__init__中创建实例属性。

但是在这种情况下,我根本不会将str.lower存储为属性值。我会存储None并在您仍然遇到str.lower时退回到None

return data.rename(columns=self.my_func_mask or str.lower)

my_func_mask设置为None可以更好地表明将使用默认值,这与将str.lower显式设置为掩码明显不同。

答案 1 :(得分:1)

Everything that is placed in the class definition is bound to the class, but you can't bind a built-in to your own class.

Essentially, all code that you place in a class is executed when the class is created. All items in locals() are then bound to your class at the end of the class. That's why this also works to bind a method to your class:

def abc(self):
    print('{} from outside the class'.format(self))

class A:
    f1 = abc
    f2 = lambda self: print('{} from lambda'.format(self))
    def f3(self):
        print('{} from method'.format(self))

To not have the function bound to your class, you have to place it in the __init__ method of your class:

class A:
    def __init__(self):
        self.my_func_mask = str.lower

答案 2 :(得分:0)

您需要声明静态方法。

class A:
    my_func_mask = staticmethod(str.lower)
    foo = 'bar'

>>> A().my_func_mask is str.lower
>>> True