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 TypeError
s 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!
答案 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