Python 类型提示:解决循环依赖关系

Python 类型提示:解决循环依赖关系,python,type-hinting,python-3.5,Python,Type Hinting,Python 3.5,以下内容产生了NameError:未定义名称“客户端”。我怎样才能解决它 class Server(): def register_client(self, client: Client) pass class Client(): def __init__(self, server: Server): server.register_client(self) 您可以通过为尚未定义的客户机类使用字符串名称来使用: class Server():

以下内容产生了
NameError:未定义名称“客户端”
。我怎样才能解决它

class Server():
    def register_client(self, client: Client)
        pass


class Client():
    def __init__(self, server: Server):
        server.register_client(self)
您可以通过为尚未定义的
客户机
类使用字符串名称来使用:

class Server():
    def register_client(self, client: 'Client')
        pass
,您还可以通过在模块顶部添加以下
\uuuuuuu future\uuuuuu
导入来推迟所有注释的运行时解析:

from __future__ import annotations
此时注释存储为表达式的抽象语法树的字符串表示形式;您可以使用来解析这些(并解析上面使用的转发引用)


详情见:;这种行为将是Python 4.0中的默认行为。

如果您使用的是Python 3.7+,请在另一个答案中使用来自“未来”导入注释的
。但是,如果由于操作系统的限制(如2019-06-03的Cygwin),您还不能使用3.7,则可以使用模块来满足这些类型的正向/循环依赖问题

请原谅这个人为的例子,但这应该说明这种方法的有用性

class Server():
    clients: list = None

    def __init__(self):
        self.clients=[]

    def register_client(self, client: 'Client') -> None:
        self.clients.append(client)
        print('Client `%s` registered with server' % client.name)

    def print_clients(self) -> None:
        for i, client in enumerate(self.clients):
            print('client %i: %s' % (i, client.name))

    @staticmethod
    def build_clone(server: 'Server') -> 'Server':
        svr_new: Server = Server()
        for client in server.clients:
            svr_new.register_client(client)
        return svr_new

class Client():
    name: str = None
    def __init__(self, name: str, server: 'Server'):
        self.name = name
        server.register_client(self)


svr = Server()
cli = Client('foo', svr)
svr.print_clients()

svr_clone = Server.build_clone(svr)
svr_clone.print_clients()

编写第三个只实现服务器的类,用客户端扩展它。注意,从Python3.7开始,不再需要在这里使用字符串前向引用,而是添加一个
from\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这种行为显然会在默认情况下被启用。@MartijnPieters我试图确认,无论类名或字符串文字如何,它对Python都无所谓,因为它不会改变性能。因此,类型提示实际上是针对第三方工具,以获得最大的好处和解决方案,对吗?(忽略自我记录的代码片段)@意大利面酱:正确。基本上,类型提示会在加载模块所需的时间上增加非常少的时间。使用
from\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。Python版本是3.7。你知道为什么它不起作用吗?为了详细说明我的观点,如果你没有定义注释类型,而是使用类型别名,这个解决方案就不起作用了:
MyType1=typing.Union[str,MyType2]MyType2=typing.Mapping[str,MyType1]
在这种情况下,你仍然会得到一个
NameError
QQ:你用pyr测试过上面的问题吗?这种方法更适合我尝试做的事情,然而,pyre似乎非常适合我confused@urban-从未使用过pyre,只是第一次阅读。看起来是个有趣的项目。我会试一试。@urban-我确实查看了pyre工具,发现了与使用类型库有关的几个问题。派尔似乎是在逐案处理问题。任何想编写一个简单的测试用例并在PyreGithub页面上提出问题的人,都可以得到解决。对我来说,我已经找到了摆脱Python3.6的方法,因此现在可以使用来自未来的注释库。祝你好运。这个答案中建议的方法是无效的,如果你不同意,mypy会报告一大堆错误。
T_服务器
服务器
,或者
T_客户端
客户端
@Monica之间没有实际连接-感谢您提供的信息。你可能是对的,但这确实使我摆脱了困境。此后,我已经了解了如何将我的所有系统安装到Python3.7+上,因此,除了一些可能陷入类似场景的人之外,我永远不会使用或推荐这种方法,因为他们的工作流中不需要静态类型分析。