类方法的functools.partial

时间:2013-05-18 16:56:03

标签: python exception methods functools

我正在尝试使用另一种更通用的类方法来定义一些类方法,如下所示:

class RGB(object):
    def __init__(self, red, blue, green):
        super(RGB, self).__init__()
        self._red = red
        self._blue = blue
        self._green = green

    def _color(self, type):
        return getattr(self, type)

    red = functools.partial(_color, type='_red')
    blue = functools.partial(_color, type='_blue')
    green = functools.partial(_color, type='_green')

但是当我尝试调用任何这些方法时,我得到:

rgb = RGB(100, 192, 240)
print rgb.red()
TypeError: _color() takes exactly 2 arguments (1 given)

我认为自_color起作用后,自我不会传递给rgb.red(rgb)

2 个答案:

答案 0 :(得分:43)

您正在函数上创建部分内容,而不是方法。 functools.partial()个对象不是描述符,它们本身不会添加self参数,也不能自己充当方法。您只能 包装绑定的方法或函数,它们根本不适用于未绑定的方法。这是documented

  

partial个对象就像function个对象,因为它们是可调用的,弱引用的,并且可以具有属性。有一些重要的区别。例如,__name____doc__属性不会自动创建。此外,类中定义的partial对象的行为类似于静态方法,并且在实例属性查找期间不会转换为绑定方法。

使用property代替;这些描述符:

class RGB(object):
    def __init__(self, red, blue, green):
        super(RGB, self).__init__()
        self._red = red
        self._blue = blue
        self._green = green

    def _color(self, type):
        return getattr(self, type)

    @property
    def red(self): return self._color('_red')
    @property
    def blue(self): return self._color('_blue')
    @property
    def green(self): return self._color('_green')

从Python 3.4开始,你可以在这里使用新的functools.partialmethod() object;绑定到实例时它会做正确的事情:

class RGB(object):
    def __init__(self, red, blue, green):
        super(RGB, self).__init__()
        self._red = red
        self._blue = blue
        self._green = green

    def _color(self, type):
        return getattr(self, type)

    red = functools.partialmethod(_color, type='_red')
    blue = functools.partialmethod(_color, type='_blue')
    green = functools.partialmethod(_color, type='_green')

但必须调用这些,而property个对象可以用作简单属性。

答案 1 :(得分:0)

partialmethod的问题在于它与inspect.signaturefunctools.wraps,...不兼容。

很奇怪,如果您使用partial documentation implementation example重新实现functools.partial,它将可以正常工作:

# Implementation from:
# https://docs.python.org/3/library/functools.html#functools.partial
def partial(func, /, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = {**keywords, **fkeywords}
        return func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc
class RGB(object):
    def __init__(self, red, blue, green):
        super(RGB, self).__init__()
        self._red = red
        self._blue = blue
        self._green = green

    def _color(self, type):
        return getattr(self, type)

    red = partial(_color, type='_red')
    blue = partial(_color, type='_blue')
    green = partial(_color, type='_green')

rgb = RGB(100, 192, 240)
print(rgb.red())  # Print red

原因是newfunc是用newfunc.__get__实现descriptor protocol的真实函数。 type(functools.partial)是一个自定义类,其中__call__被覆盖。类不会自动添加self参数。