编程语言
首页 > 编程语言> > python – 如何指定方法的返回类型与类本身相同?

python – 如何指定方法的返回类型与类本身相同?

作者:互联网

我在python 3中有以下代码:

class Position:

    def __init__(self, x: int, y: int):
        self.x = x
        self.y = y

    def __add__(self, other: Position) -> Position:
        return Position(self.x + other.x, self.y + other.y)

但是我的编辑器(PyCharm)说无法解析引用位置(在__add__方法中).我应该如何指定我希望返回类型为Position类型?

编辑:我认为这实际上是一个PyCharm问题.它实际上使用其警告中的信息和代码完成

但如果我错了,请纠正我,并需要使用其他语法.

解决方法:

TL; DR:如果您使用的是Python 4.0,它就可以了.从今天(2019年)的3.7开始,您必须使用将来的语句(来自__future__ import annotations)来启用此功能 – 对于Python 3.6或更低版本,请使用字符串.

我猜你有这个例外:

NameError: name 'Position' is not defined

这是因为必须先定义Position,然后才能在注释中使用它,除非您使用的是Python 4.

Python 3.7:来自__future__ import annotations

Python 3.7引入了PEP 563: postponed evaluation of annotations.使用__future__ import annotations的future语句的模块将自动将注释存储为字符串:

from __future__ import annotations

class Position:
    def __add__(self, other: Position) -> Position:
        ...

这计划成为Python 4.0中的默认设置.由于Python仍然是动态类型语言,因此在运行时不进行类型检查,因此键入注释应该不会对性能产生影响,对吧?错误!在python 3.7之前,输入模块曾经是one of the slowest python modules in core,所以如果你导入输入,你会在升级到3.7时看到up to 7 times increase in performance.

Python< 3.7:使用字符串 According to PEP 484,你应该使用一个字符串而不是类本身:

class Position:
    ...
    def __add__(self, other: 'Position') -> 'Position':
       ...

如果你使用Django框架,这可能是熟悉的,因为Django模型也使用字符串作为前向引用(外键模型是自己的或未声明的外键定义).这应该适用于Pycharm和其他工具.

来源

PEP 484PEP 563的相关部分,为您带来免费旅行:

Forward references

When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.

A situation where this occurs commonly is the definition of a container class, where the class being defined occurs in the signature of some of the methods. For example, the following code (the start of a simple binary tree implementation) does not work:

class Tree:
    def __init__(self, left: Tree, right: Tree):
    self.left = left
    self.right = right

To address this, we write:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

The string literal should contain a valid Python expression (i.e., compile(lit, ”, ‘eval’) should be a valid code object) and it should evaluate without errors once the module has been fully loaded. The local and global namespace in which it is evaluated should be the same namespaces in which default arguments to the same function would be evaluated.

和PEP 563:

In Python 4.0, function and variable annotations will no longer be evaluated at definition time. Instead, a string form will be preserved in the respective __annotations__ dictionary. Static type checkers will see no difference in behavior, whereas tools using annotations at runtime will have to perform postponed evaluation.

The functionality described above can be enabled starting from Python 3.7 using the following special import:

from __future__ import annotations

你可能想要做的事情

A.定义虚拟位置

在类定义之前,放置一个虚拟定义:

class Position(object):
    pass


class Position(object):
    ...

这将摆脱NameError甚至可能看起来不错:

>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}

但是吗?

>>> for k, v in Position.__add__.__annotations__.items():
...     print(k, 'is Position:', v is Position)                                                                                                                                                                                                                  
return is Position: False
other is Position: False

B.猴子补丁以添加注释:

您可能想尝试一些Python元编程魔术并编写装饰器
修补类定义以添加注释:

class Position:
    ...
    def __add__(self, other):
        return self.__class__(self.x + other.x, self.y + other.y)

装饰者应该负责相当于:

Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position

至少看起来是对的:

>>> for k, v in Position.__add__.__annotations__.items():
...     print(k, 'is Position:', v is Position)                                                                                                                                                                                                                  
return is Position: True
other is Position: True

可能太麻烦了.

结论

如果您使用的是3.6或更低版本,请使用包含类名的字符串文字,在3.7中使用__future__ import注释,它就可以正常工作.

标签:python-3-5,python,python-3-x,pycharm,typing
来源: https://codeday.me/bug/20190911/1804359.html