类方法的functools.partial

Arj*_*jor 35 python methods exception 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')
Run Code Online (Sandbox Code Playgroud)

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

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

我想_color自从rgb.red(rgb)工作以来,自我没有被传递.

Mar*_*ers 45

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

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

propertys代替; 这些描述符:

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')
Run Code Online (Sandbox Code Playgroud)

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

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')
Run Code Online (Sandbox Code Playgroud)

但这些必须被调用,而property对象可以用作简单的属性.

  • @dashesy:当然,但是这会将这些对象放在每个实例上(内存成本),也会让子类更难以替换它们. (5认同)
  • __init__中的`self.red = functools.partial(RGB._color,self,'red')`呢?它也与Python2兼容。 (4认同)

Con*_*tor 8

问题是它与, ,...partialmethod不兼容inspect.signaturefunctools.wraps

奇怪的是,如果您使用部分文档实现示例重新实现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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

原因是这newfunc是一个真正的函数,它实现了描述符协议newfunc.__get__。Whiletype(functools.partial)是一个被覆盖的自定义类__call__。类不会self自动添加参数。