使用严格静态类型检查时的循环导入

2024-06-28 19:13:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在做一个项目,我决定使用这个类图:

在测试期间,它工作得很好,所以我决定正确地执行它,并确保指定所有类型只是为了避免将来出现问题。问题是,要做到这一点,我需要导入更多的类,而我最终需要循环导入

我在一些地方读到过,这个问题通常是因为一个糟糕的设计。我认为情况并非如此。在其他地方,我读到我不应该检查类型。这是一个选择,但这是一个我不喜欢的选择。我也读过其他解决这个问题的方法,但它们似乎都不是真正的解决办法

我知道Python不是Java,但由于产生问题的导入只是用于指定方法的参数类型,我认为可能有一种方法可以在Python程序中指定这一类型,因此循环导入不会避免程序的执行

谢谢,如果您需要任何其他信息,请询问,我会尽快答复

编辑:

这是终端的输出:

[edoelas@leonardo server]$ env DEBUGPY_LAUNCHER_PORT=44765 /usr/bin/python /home/edoelas/.vscode/extensions/ms-python.python-2020.3.71113/pythonFiles/lib/python/debugpy/no_wheels/debugpy/launcher /home/edoelas/git/tfg/server/main.py 
Traceback (most recent call last):
  File "/home/edoelas/git/tfg/server/main.py", line 1, in <module>
    from classes.actions.Move import Move
  File "/home/edoelas/git/tfg/server/classes/actions/Move.py", line 2, in <module>
    from classes.Entity import Entity
  File "/home/edoelas/git/tfg/server/classes/Entity.py", line 3, in <module>
    from classes.ActionType import ActionType
  File "/home/edoelas/git/tfg/server/classes/ActionType.py", line 5, in <module>
    from classes.Entity import Entity 
ImportError: cannot import name 'Entity' from partially initialized module 'classes.Entity' (most likely due to a circular import) (/home/edoelas/git/tfg/server/classes/Entity.py)

这些是涉及的文件:

Main.py

from classes.actions.Move import Move
from classes.Position import Position
from classes.Game import Game
from classes.Entity import Entity
from classes.Client import Client
from classes.Map import Map



if __name__ == "__main__":

    map1 = Map()

    client1 = Client("localhost",1000)
    position1 = Position(0,0)
    action1 = Move()
    entity1 = Entity("test",100,1,[action1],client1,position1,map1)
    id1 = 1
    entity1.id = id1

    ground_matrix = [
        [0,0,0,0],
        [0,0,0,0],
        [0,0,0,0],
        [0,0,0,0],
    ]

    entity_matrix = [
        [id1,0,0,0],
        [0,0,0,0],
        [0,0,0,0],
        [0,0,0,0],
    ]
    map1.load_map(ground_matrix,entity_matrix)

    game = Game("ip", 1000, "asd")
    game.add_entity(entity1)

    print(map1.entity_matrix)
    print(entity1.position)

    position2 = Position(1,0)
    entity1.loadAction(action1,position2)
    entity1.executeAction()

    action1.emiting_area

    print(map1.entity_matrix)
    print(entity1.position)

Move.py

from classes.Position import Position
from classes.Entity import Entity
from classes.ActionType import ActionType
from classes.Area import Area

class Move(ActionType):
    def __init__(self):
        self.emiting_area

    @property
    def emiting_area(self) -> Area:
        return self.__emiting_area

    @emiting_area.setter
    def emiting_area(self, emiting_area: Area) -> None:
        self.__emiting_area = emiting_area

    def execute(self,emitter: Entity,target_position: Position) -> None:
        emitter.position = target_position

Entity.py

# pyright: strict

from classes.ActionType import ActionType
from classes.Map import Map
from classes.Position import Position
from classes.Client import Client
from classes.Action import Action
from typing import List

class Entity:
    """
    The entities are added from the Game object
    """
    def __init__(self, name: str, max_health: int,team: int,
    possible_actions: List[ActionType], client: Client,position: Position,map: Map):
        self.__id: int
        self.__name: str = name
        self.max_health: int= max_health
        self.team: int = team
        self.health: int = max_health
        self.possible_actions: List[ActionType] = possible_actions
        self.__action_buffer: List[Action] = []
        self.client: Client = client
        self.__position: Position = position
        #Map is here in order to update it each time an entity moves
        self.map: Map = map


    @property
    def position(self) -> Position:
        return self.__position

    @position.setter
    def position(self, new_position: Position):
        self.__position = new_position
        self.map.update_entity(self.id,self.__position,new_position)


    @property
    def id(self) -> int:
        return self.__id

    @id.setter
    def id(self,id: int):
        #Si la id ya ha sido asignada lanzar error
        self.__id = id


    def loadAction(self,actionType: ActionType,target_position: Position) -> None:
        action = Action(actionType, self,target_position)
        self.__action_buffer.append(action)

    def executeAction(self) -> None:
        action = self.__action_buffer.pop(0)
        action.execute()

ActionType.py

# pyright: strict

from abc import abstractmethod
from classes.Position import Position
from classes.Entity import Entity 

class ActionType:
    def __init__(self):
        raise NotImplementedError

    @property
    @abstractmethod
    def emiting_area(self) -> None:
        raise NotImplementedError

    @property
    @abstractmethod
    def receiving_area(self) -> None:
        raise NotImplementedError

    @abstractmethod
    def execute(self,emiter: Entity,target_position: Position) -> None:
        raise NotImplementedError

Tags: frompyimportselfidmovedefposition