Доступ к вложенному классу из другого вложенного класса данных - PullRequest
1 голос
/ 02 октября 2019

Теперь следующий код прекрасно работает с Python 3.7

class A:
    class B:
        def __init__(self):
            print("B")

    class C:
        def __init__(self):
            self.b = A.B()

def main():
    a = A.C()

if __name__ == "__main__":
    main()

. Он печатает B на экране.

Однако, с небольшой модификацией, которая пытается представить класс данных,код не может работать хорошо.

from dataclasses import dataclass

class A:
    class B:
        def __init__(self):
            print("B")

    @dataclass
    class C:
        b = A.B()

def main():
    a = A.C()

if __name__ == "__main__":
    main()

Отчеты Python - для b = A.B() - NameError: name 'A' is not defined.

Кто-нибудь знает, как решить эту проблему, чтобы добиться того же результата с помощью класса данных? И почему это говорит name 'A' is not defined?

Ответы [ 2 ]

2 голосов
/ 02 октября 2019

Объект класса не создается до тех пор, пока не будет достигнут конец тела оператора class, поэтому на ваш класс A нельзя ссылаться, пока он еще определен. Ссылка A внутри метода __init__, с другой стороны, действительна, поскольку класс A уже определен при вызове метода __init__.

Вместо этого можно использовать typing.TypeVar дляопределить тип прямой ссылки A.B для b и присвоить ему значение по умолчанию field с помощью функции default_factory, которая возвращает экземпляр A.B при вызове:

from dataclasses import dataclass, field
from typing import TypeVar

class A:
    class B:
        def __init__(self):
            print("B")

    @dataclass
    class C:
        b: TypeVar('A.B') = field(default_factory=lambda: A.B())

def main():
    a = A.C()

if __name__ == "__main__":
    main()

Это выводит:

B
0 голосов
/ 02 октября 2019

Другой способ отложить инициализацию до определения и доступности class A, не касаясь сгенерированных __init__:

@dataclass
class C:
    b: TypeVar('A.B') = field(init=False)

def __post_init__(self):
    self.b = A.B()

Пожалуйста, обратитесь к официальным документам

...