问题
Python 函数有比较缺陷(见下面的打印(。但他们NotImplemented
.很公平。但是它们的预期用途是什么,以及如何使用它们?当我将可调用对象分配给func.__gt__
时,我没有看到它被调用func < other_func
。
示例代码
我可以看到(foo > bar)
的用途是等同于lambda x: foo(x) > bar(x)
的函数,但同样(可以说更有用(,它可以用来构造管道。
例如,我们可以有
def composeable(func):
func.__gt__ = lambda g: lambda x: g(f(x))
func.__lt__ = lambda g: lambda x: f(g(x))
return func
可以用作
>>> def composeable(func):
... func.__gt__ = lambda g: lambda x: g(f(x))
... func.__lt__ = lambda g: lambda x: f(g(x))
... return func
...
>>> @composeable
... def f(x):
... return x + 2
...
>>> def g(x):
... return x * 10
...
>>> h = f.__gt__(g)
>>> assert h(3) == 50 # (3 + 2) * 10
>>> h = f.__lt__(g)
>>> assert h(3) == 32 # (3 * 10) + 2
然而,越来越好奇,这行不通:
>>> h = f > g
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'function' and 'function'
注意:可调用的NotImplemented
函数会沉没。
__eq__: NotImplemented
__ge__: NotImplemented
__gt__: NotImplemented
__le__: NotImplemented
__lt__: NotImplemented
__ne__: NotImplemented
生成上述打印输出的代码:
from inspect import signature
def f(x): ...
for aname in dir(f):
attr = getattr(f, aname)
if callable(attr):
try:
x = attr(*len(signature(attr).parameters) * [''])
if x is NotImplemented:
print(f"{aname}: NotImplemented")
except Exception as e:
pass
您可以做的最简单的事情是定义一个支持组合的包装器。由于比较运算符的处理,我建议使用>>
和<<
进行组合。
# Assumption: the wrapped callable take a single argument
class ComposableCallable:
def __init__(self, func):
self.func = func
def __lshift__(self, other):
@ComposableCallable
def _(x):
return self.func(other.func(x))
return _
def __rshift__(self, other):
@ComposableCallable
def _(x):
return other.func(self.func(x))
return _
def __call__(self, x):
return self.func(x)
@ComposableCallable
def f(x):
return x + 1
@ComposableCallable
def g(x):
return 2 * x
assert (f << g)(3) == 7 # 2*3 + 1 == 7
assert (f >> g)(3) == 8 # (3 + 1) * 2 == 8
然而,越好奇越好奇,这行不通:
这与 dunder 方法的实现无关,而与您尝试修改内置函数类型的现有行为这一事实有关。您将无法修改基础类,并且将忽略在实例上分配这些属性。
如何使用它们,以及应该如何使用它们。
您可以将它们用于您自己的类,其中实例之间存在自然的比较。例如,标准库fractions.Fraction
类支持这些比较;并在 Python 中实现,需要使用这些方法。
它可用于构建管道。
啊
这非常违背了Python的禅意。它还没有以这种方式工作是有原因的。恕我直言,Numpy 与运营商一起做的事情已经在推动它,并且大多被容忍,因为它们非常有用。(此外,正如评论中指出的那样,Python 对链式关系运算符的特殊处理将使它无法按照您希望的方式在非平凡的情况下工作。