不能使用部分作为 __str__
Can't use partial as __str__
我 运行 在尝试为我使用几个包含浮点对的命名元组的程序编写漂亮的打印过程时遇到了这个问题。
from collections import namedtuple
Position = namedtuple('Position', 'x y')
Vector = namedtuple('Vector', 'x y')
Size = namedtuple('Size', 'width height')
我想在打印时格式化浮点数,因为结果:
import math
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))
太长了:
Position(x=3.141592653589793, y=3.141592653589793) Vector(x=3.141592653589793, y=3.141592653589793) Size(width=3.141592653589793, height=3.141592653589793)
所以我创建了一个函数来打印命名的元组:
def pretty_float_pair(name, labels, obj):
"""
If labels = ('a', 'b') and object = (1.2345, 1.2345) returns:
'name(a=1.23, b=1.23)'
"""
return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1])
每种类型的名称和标签都应该是固定的,只有 obj 参数不同,所以我想我可以使用 functools partial。
from functools import partial
Position.__str__ = partial(pretty_float_pair, 'Position', ('x', 'y'))
Vector.__str__ = partial(pretty_float_pair, 'Vector', ('x', 'y'))
Size.__str__ = partial(pretty_float_pair, 'Size', ('width', 'height'))
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))
但这会引发 TypeError: pretty_float_pair() missing 1 required positional argument: 'obj'.
令人惊讶的是,如果我使用 lambda 来创建它可以工作的函数。
Position.__str__ = lambda x: pretty_float_pair('Position', ('x', 'y'), x)
Vector.__str__ = lambda x: pretty_float_pair('Vector', ('x', 'y'), x)
Size.__str__ = lambda x: pretty_float_pair('Size', ('width', 'height'), x)
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))
打印我想要的:
Position(x=3.14, y=3.14) Vector(x=3.14, y=3.14) Size(width=3.14, height=3.14)
我正在尝试了解为什么部分版本不起作用。
函数通过 descriptors 获得它们的隐式 self
参数:查找 x.f
构造和 return 一个方法对象,它记住 x
以便将其提供给 f
。 functools.partial(...)
不是 return 描述符,所以它没有得到那种特殊对待。 (它实际上是一个 class,所以它 "returns" 是它自己的一个实例。)
functools.partial
returns 一个非描述符可调用对象,大致相当于一个未绑定的方法。这意味着它没有传递 self
参数,这与您看到的错误一致。
由于 lambda 的行为就像使用 def
定义的常规函数一样,它实际上是一个描述符。 lambda 的 __get__
方法 returns 作为 x
.
在实例中传递的绑定版本
要获得更像方法的部分函数,请改用 functools.partialmethod
。您必须将 obj
移动到参数列表的开头,以便它可以在绑定方法时接收 self
。
这是你的例子:
from functools import partialmethod
def pretty_float_pair(obj, name, labels):
"""
If labels = ('a', 'b') and object = (1.2345, 1.2345), returns:
name(a=1.23, b=1.23)
"""
return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1])
Position.__str__ = partialmethod(pretty_float_pair, 'Position', ('x', 'y'))
Vector.__str__ = partialmethod(pretty_float_pair, 'Vector', ('x', 'y'))
Size.__str__ = partialmethod(pretty_float_pair, 'Size', ('width', 'height'))
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))
我 运行 在尝试为我使用几个包含浮点对的命名元组的程序编写漂亮的打印过程时遇到了这个问题。
from collections import namedtuple
Position = namedtuple('Position', 'x y')
Vector = namedtuple('Vector', 'x y')
Size = namedtuple('Size', 'width height')
我想在打印时格式化浮点数,因为结果:
import math
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))
太长了:
Position(x=3.141592653589793, y=3.141592653589793) Vector(x=3.141592653589793, y=3.141592653589793) Size(width=3.141592653589793, height=3.141592653589793)
所以我创建了一个函数来打印命名的元组:
def pretty_float_pair(name, labels, obj):
"""
If labels = ('a', 'b') and object = (1.2345, 1.2345) returns:
'name(a=1.23, b=1.23)'
"""
return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1])
每种类型的名称和标签都应该是固定的,只有 obj 参数不同,所以我想我可以使用 functools partial。
from functools import partial
Position.__str__ = partial(pretty_float_pair, 'Position', ('x', 'y'))
Vector.__str__ = partial(pretty_float_pair, 'Vector', ('x', 'y'))
Size.__str__ = partial(pretty_float_pair, 'Size', ('width', 'height'))
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))
但这会引发 TypeError: pretty_float_pair() missing 1 required positional argument: 'obj'.
令人惊讶的是,如果我使用 lambda 来创建它可以工作的函数。
Position.__str__ = lambda x: pretty_float_pair('Position', ('x', 'y'), x)
Vector.__str__ = lambda x: pretty_float_pair('Vector', ('x', 'y'), x)
Size.__str__ = lambda x: pretty_float_pair('Size', ('width', 'height'), x)
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))
打印我想要的:
Position(x=3.14, y=3.14) Vector(x=3.14, y=3.14) Size(width=3.14, height=3.14)
我正在尝试了解为什么部分版本不起作用。
函数通过 descriptors 获得它们的隐式 self
参数:查找 x.f
构造和 return 一个方法对象,它记住 x
以便将其提供给 f
。 functools.partial(...)
不是 return 描述符,所以它没有得到那种特殊对待。 (它实际上是一个 class,所以它 "returns" 是它自己的一个实例。)
functools.partial
returns 一个非描述符可调用对象,大致相当于一个未绑定的方法。这意味着它没有传递 self
参数,这与您看到的错误一致。
由于 lambda 的行为就像使用 def
定义的常规函数一样,它实际上是一个描述符。 lambda 的 __get__
方法 returns 作为 x
.
要获得更像方法的部分函数,请改用 functools.partialmethod
。您必须将 obj
移动到参数列表的开头,以便它可以在绑定方法时接收 self
。
这是你的例子:
from functools import partialmethod def pretty_float_pair(obj, name, labels): """ If labels = ('a', 'b') and object = (1.2345, 1.2345), returns: name(a=1.23, b=1.23) """ return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1]) Position.__str__ = partialmethod(pretty_float_pair, 'Position', ('x', 'y')) Vector.__str__ = partialmethod(pretty_float_pair, 'Vector', ('x', 'y')) Size.__str__ = partialmethod(pretty_float_pair, 'Size', ('width', 'height')) print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))