Тип подсказок: решить круговую зависимость

В результате получается NameError: name 'Client' is not defined. Как я могу его решить?

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


class Client():
    def __init__(self, server: Server):
        server.register_client(self)

Ответ 1

Вы можете использовать прямую ссылку, используя строковое имя для еще не определенного класса Client:

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

Начиная с Python 3.7, вы также можете отложить анализ аннотаций во время выполнения, добавив следующий импорт __future__ вверху модуля:

from __future__ import annotations

в этот момент аннотации сохраняются в виде строковых представлений абстрактного синтаксического дерева для выражения; Вы можете использовать typing.get_type_hints() чтобы разрешить их (и разрешить прямые ссылки, как указано выше).

См. PEP 563 - Отложенная оценка аннотаций для деталей; это поведение будет по умолчанию в Python 4.0.

Ответ 2

Если вы используете Python 3. 7+, используйте from __future__ import annotations как упомянуто в другом ответе. Однако, если вы еще не можете использовать 3.7 из-за ограничений ОС (например, Cygwin от 2019-06-03), вы можете использовать модуль ввода для решения этих типов проблем прямой/циклической зависимости.

Простите за надуманный пример, но это должно проиллюстрировать полезность этой методологии.

from typing import TypeVar, Generic

T_Server = TypeVar('T_Server')
T_Client = TypeVar('T_Client')


class Server(Generic[T_Server]):
    clients: list = None

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

    def register_client(self, client: T_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: T_Server) -> T_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: T_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()