Rus*_*ott 7 python function-composition python-decorators
在这个问题中,我询问了Python中的函数组合运算符。@Philip Tzou提供了以下代码,它可以完成这项工作。
import functools
class Composable:
def __init__(self, func):
self.func = func
functools.update_wrapper(self, func)
def __matmul__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
def __call__(self, *args, **kw):
return self.func(*args, **kw)
Run Code Online (Sandbox Code Playgroud)
我添加了以下功能。
def __mul__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
def __gt__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
Run Code Online (Sandbox Code Playgroud)
通过这些添加,我们可以使用@、*和>as 运算符来组成函数。例如,我们可以编写print((add1 @ add2)(5), (add1 * add2)(5), (add1 > add2)(5))并获取# 8 8 8. (PyCharm 抱怨布尔值不可调用(add1 > add2)(5)。但它仍然运行。)
不过,我一直想将其.用作函数组合运算符。所以我添加了
def __getattribute__(self, other):
return lambda *args, **kw: self.func(other.func(*args, **kw))
Run Code Online (Sandbox Code Playgroud)
(请注意,这会弄乱update_wrapper,为了这个问题可以将其删除。)
当我运行时,print((add1 . add2)(5))我在运行时收到此错误:AttributeError: 'str' object has no attribute 'func'。事实证明(显然)参数 to__getattribute__在传递给 之前被转换为字符串__getattribute__。
有没有办法绕过这种转换?或者我是否误诊了问题,而其他方法会起作用?
你无法拥有你想要的。该.表示法不是二元运算符,它是一个主运算符,仅包含值操作数( 的左侧).和标识符。标识符是字符串,而不是生成对值的引用的完整表达式。
从属性参考部分:
属性引用是主要的,后跟句点和名称:
Run Code Online (Sandbox Code Playgroud)attributeref ::= primary "." identifier主对象必须求值为支持属性引用的类型的对象,大多数对象都支持属性引用。然后要求该对象生成名称为标识符的属性。
因此,在编译时,Python 会解析identifier为字符串值,而不是表达式(这是运算符的操作数得到的表达式)。该__getattribute__钩子(以及任何其他属性访问钩子)只需处理字符串。这是没有办法解决的;动态属性访问函数getattr()严格强制name必须是字符串:
>>> getattr(object(), 42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
Run Code Online (Sandbox Code Playgroud)
如果要使用语法来组合两个对象,则仅限于二元运算符,因此需要两个操作数的表达式,并且只有那些具有钩子的表达式(布尔值and和or运算符没有钩子,因为它们计算延迟,is并且is not没有钩子因为它们对对象标识进行操作,而不是对对象值进行操作)。
我其实不愿意提供这个答案。但您应该知道在某些情况下您可以使用点“ .”符号,即使它是主要的。该解决方案仅适用于可以从以下位置访问的功能globals():
import functools
class Composable:
def __init__(self, func):
self.func = func
functools.update_wrapper(self, func)
def __getattr__(self, othername):
other = globals()[othername]
return lambda *args, **kw: self.func(other.func(*args, **kw))
def __call__(self, *args, **kw):
return self.func(*args, **kw)
Run Code Online (Sandbox Code Playgroud)
去测试:
@Composable
def add1(x):
return x + 1
@Composable
def add2(x):
return x + 2
print((add1.add2)(5))
# 8
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5635 次 |
| 最近记录: |