Last active
June 26, 2019 08:01
-
-
Save kurtgn/482eb0033ad3122fd7108bd06bf0a402 to your computer and use it in GitHub Desktop.
mypy circular import problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# circular import: | |
# node.py | |
from typing import Iterable | |
from nodeset import NodeSet | |
from typing import Iterable | |
from abstract_node import AbstractNode | |
from nodeset import NodeSet | |
class Node: | |
def __init__(self, name): | |
self.name = name | |
self.children = NodeSet() | |
def do_stuff(self) -> None: | |
print(f'node {self.name} does stuff') | |
def descendants(self) -> Iterable['Node']: | |
for child in self.children.all_nodes(): | |
yield child | |
yield from child.descendants() | |
# nodeset.py | |
from typing import Iterable, List | |
from node import Node | |
class NodeSet: | |
def __init__(self): | |
self.nodes: List[Node] = [] | |
def insert(self, node: Node) -> None: | |
self.nodes.append(node) | |
def all_nodes(self) -> Iterable[Node]: | |
for node in self.nodes: | |
yield node | |
# app.py | |
from node import Node | |
n = Node('a') | |
n.children.insert(Node('b')) | |
n.children.insert(Node('c')) | |
n.children.insert(Node('d')) | |
root = Node('r') | |
root.children.insert(n) | |
for d in root.descendants(): | |
d.do_stuff() | |
# если запустить это: | |
Traceback (most recent call last): | |
File "/Users/1111/_projects/fasttrack/constructor/run_nodes.py", line 3, in <module> | |
from node import Node | |
File "/Users/1111/_projects/fasttrack/constructor/node.py", line 4, in <module> | |
from nodeset import NodeSet | |
File "/Users/1111/_projects/fasttrack/constructor/nodeset.py", line 3, in <module> | |
from node import Node | |
ImportError: cannot import name 'Node' | |
# =========================================== | |
# Решение проблемы: наследуем ноду от AbstractNode. | |
# NodeSet не обязан знать, что у него в списке лежат именно ноды. Пусть знает только об AbstractNode | |
# abstract_node.py | |
from abc import ABC, abstractmethod | |
from typing import Iterable | |
class AbstractNode(ABC): | |
@abstractmethod | |
def descendants(self) -> Iterable['AbstractNode']: | |
pass | |
@abstractmethod | |
def do_stuff(self) -> None: | |
pass | |
# node_set.py | |
# NodeSet не обязан знать, что у него в списке хранятся именно ноды. Это всего лишь коллекция. | |
# пусть знает только об интерфейсе | |
from typing import Iterable, List | |
from abstract_node import AbstractNode | |
class NodeSet: | |
def __init__(self): | |
self.nodes: List[AbstractNode] = [] | |
def insert(self, node: AbstractNode) -> None: | |
self.nodes.append(node) | |
def all_nodes(self) -> Iterable[AbstractNode]: | |
for node in self.nodes: | |
yield node | |
def all_descendants(self) -> Iterable[AbstractNode]: | |
for node in self.nodes: | |
yield node | |
yield from node.descendants() | |
# node.py | |
from typing import Iterable | |
from abstract_node import AbstractNode | |
from nodeset import NodeSet | |
class Node(AbstractNode): | |
def __init__(self, name): | |
self.name = name | |
self.children = NodeSet() | |
def do_stuff(self) -> None: | |
print(f'node {self.name} does stuff') | |
def descendants(self) -> Iterable['AbstractNode']: | |
yield from self.children.all_descendants() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment