如何在类属性中存储函数?

时间:2015-02-09 17:25:02

标签: python

在我的代码中,我有一个类,其中一个方法负责过滤一些数据。为了允许后代的自定义,我想将过滤函数定义为类属性,如下所示:

def my_filter_func(x):
    return x % 2 == 0

class FilterClass(object):

    filter_func = my_filter_func

    def filter_data(self, data):
        return filter(self.filter_func, data)

class FilterClassDescendant(FilterClass):

    filter_func = my_filter_func2

但是,这样的代码会导致TypeError,因为filter_func接收“self”作为第一个参数。 处理此类用例的pythonic方法是什么?也许,我应该将我的“filter_func”定义为常规类方法?

2 个答案:

答案 0 :(得分:4)

您可以将其添加为普通旧属性吗?

def my_filter_func(x):
    return x % 2 == 0

class FilterClass(object):

    def __init__(self):
        self.filter_func = my_filter_func

    def filter_data(self, data):
        return filter(self.filter_func, data)

或者,强迫它成为静态方法:

def my_filter_func(x):
    return x % 2 == 0

class FilterClass(object):

    filter_func = staticmethod(my_filter_func)

    def filter_data(self, data):
        return filter(self.filter_func, data)

答案 1 :(得分:2)

Python里面有很多魔力。其中一个魔法与将函数转换为UnboundMethod对象(分配给类,而不是类'实例)有关。

当你分配一个函数时(我不确定它是否适用于任何可调用函数或只是函数),Python会将它转换为UnboundMethod对象(即可以使用实例调用的对象)。

在正常情况下,您可以正常调用UnboundMethod:

def myfunction(a, b):
    return a + b

class A(object):
    a = myfunction

A.a(1, 2)
#prints 3

这不会失败。但是,当您尝试从实例中调用它时,会出现不同的情况:

A().a(1, 2)

这将失败,因为当实例获得(例如,内部getattr)属性为UnboundMethod时,它会返回此类方法的副本,并填充im_self成员(im_self并且im_func是UnboundMethod的成员。您打算调用的函数位于im_func成员中。当您调用此方法时,您实际上会使用im_func中的值实际调用im_self。因此,该函数需要一个额外的参数(第一个参数,它代表自己)。

为了避免这种魔力,Python有两个可能的装饰器:

  • 如果要按原样传递函数,则必须使用@staticmethod。在这种情况下,您将具有未转换为UnboundMethod的功能。但是,除了作为全局引用之外,您将无法访问调用类。
  • 如果你想拥有相同的,但能够访问当前的类(无论是从一个实例还是从类中调用它的函数),那么你的函数应该有另一个第一个参数(INSTEAD of self:cls )这是对类的引用,要使用的装饰器是@classmethod

示例:

class A(object):
    a = staticmethod(lambda a, b: a + b)

A.a(1, 2)
A().a(1, 2)

两者都有效。

另一个例子:

def add_print(cls, a, b):
    print cls.__name__
    return a + b

class A(object):
    ap = classmethod(add_print)

class B(A):
    pass

A.ap(1, 2)
B.ap(1, 2)
A().ap(1, 2)
B().ap(1, 2)

由yourseld检查并享受魔力。