我想用functools.singledispatchmethod来重载一个名为Polynomial的类的二进制算术运算符方法.我的问题是,我找不到一种方法来注册otherPolynomial的方法调用.

或许用一个简单的例子来解释会更好:

from __future__ import annotations
from functools import singledispatchmethod


class Polynomial:
    @singledispatchmethod
    def __add__(self, other):
        return NotImplemented

    @__add__.register
    def _(self, other: Polynomial):
        return NotImplemented

上面的代码引发NameError:

NameError: name 'Polynomial' is not defined

这个NameError不是由注释引起的,而是在functools内部引发的.此外,使用字符串'Polynomial'而不需要__future__.annotations的注释也不起作用.这一行为在the documentation for functools.singledispatchmethod中没有记录.

我可以使Polynomial继承自另一个类,然后在类型批注中使用该类,从而使其正常工作:

from functools import singledispatchmethod


class _Polynomial:
    pass


class Polynomial(_Polynomial):
    @singledispatchmethod
    def __add__(self, other):
        return NotImplemented

    @__add__.register
    def _(self, other: _Polynomial):
        return NotImplemented

..但我并不是太喜欢这个解决方案.

我如何才能在不需要无用的中间类的情况下工作呢?

推荐答案

另一种方法是在类定义之后添加方法:

from __future__ import annotations
from functools import singledispatchmethod


class Polynomial:
    pass

@singledispatchmethod
def __add__(self, other):
    return NotImplemented

@__add__.register
def _(self, other: Polynomial):
    return NotImplemented

Polynomial.__add__ = __add__

您不能在类定义期间实际引用该类,因为the class doesn't exist yet.使用from __future__ import annotations可以使批注保存为字符串,但只要修饰者try 计算这些字符串的值,就会出现同样的问题,因此它无法绕过它(因为它不仅仅是批注).

这在堆栈跟踪(略)中很明显:

~/miniconda3/envs/py39/lib/python3.9/functools.py in register(cls, func)
    858             # only import typing if annotation parsing is necessary
    859             from typing import get_type_hints
--> 860             argname, cls = next(iter(get_type_hints(func).items()))
    861             if not isinstance(cls, type):
    862                 raise TypeError(

~/miniconda3/envs/py39/lib/python3.9/typing.py in get_type_hints(obj, globalns, localns, include_extras)
   1447         if isinstance(value, str):
   1448             value = ForwardRef(value)
-> 1449         value = _eval_type(value, globalns, localns)
   1450         if name in defaults and defaults[name] is None:
   1451             value = Optional[value]

~/miniconda3/envs/py39/lib/python3.9/typing.py in _eval_type(t, globalns, localns, recursive_guard)
    281     """
    282     if isinstance(t, ForwardRef):
--> 283         return t._evaluate(globalns, localns, recursive_guard)
    284     if isinstance(t, (_GenericAlias, GenericAlias)):
    285         ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)

~/miniconda3/envs/py39/lib/python3.9/typing.py in _evaluate(self, globalns, localns, recursive_guard)
    537                 localns = globalns
    538             type_ =_type_check(
--> 539                 eval(self.__forward_code__, globalns, localns),
    540                 "Forward references must evaluate to types.",
    541                 is_argument=self.__forward_is_argument__,

因此,当singledispatchmethod修饰器typing.get_type_hints(本质上是eval)(增加的特性是小心地获取正确的全局作用域以在其中计算字符串值时,在其中进行批注的那个)

Python相关问答推荐

不理解Value错误:在Python中使用迭代对象设置时必须具有相等的len键和值

如何访问所有文件,例如环境变量

在Python Attrs包中,如何在field_Transformer函数中添加字段?

更改键盘按钮进入'

Python+线程\TrocessPoolExecutor

如何使用scipy的curve_fit与约束,其中拟合的曲线总是在观测值之下?

在单个对象中解析多个Python数据帧

joblib:无法从父目录的另一个子文件夹加载转储模型

调用decorator返回原始函数的输出

Tkinter菜单自发添加额外项目

如何在TensorFlow中分类多个类

Python全局变量递归得到不同的结果

并行编程:同步进程

如何从比较函数生成ngroup?

我什么时候应该使用帆布和标签?

如何获取包含`try`外部堆栈的`__traceback__`属性的异常

普洛特利express 发布的人口普查数据失败

有没有一种方法可以根据不同索引集的数组从2D数组的对称子矩阵高效地构造3D数组?

通过PyTorch中的MIN函数传递渐变

matplotlib散点图与NaNs和cmap colored颜色 矩阵