如何从两个不同文件中的两个不同类中获取函数以相互通信



我正在尝试制作一个基于文本的RPG。我有一些代码,比如:

heroes.py:

class Hero():
def __init__(self):
pass
def Attack(self, target):
# ...
def TakeDamage(self, amount):
# ...

monsters.py:

class Monster():
def __init__(self):
pass
def Attack(self, target):
# ...
def TakeDamage(self, amount):
# ...

整个文件结构如下:

|__ backend
__init__.py
monsters.py
heroes.py
MainGame.py

假设我希望MonsterHero访问彼此的AttackTakeDamage函数,例如:

class Monster():
def __init__(self):
pass
def Attack(self, target):
# ...
def TakeDamage(self, amount, target:Hero):
damage = # damage calculation here
target.TakeDamage(damage)

我该怎么做?到目前为止,我已经尝试过:

  • 在各自的文件中导入彼此(例如from .monsters import Monster)-这会导致读取ImportError: cannot import name 'Monster' from partially initialized module 'backend.monsters' (most likely due to a circular import)时出错

一般来说,类没有方法;类的目的是定义数据类型。为了使用实例,您不需要在Python中看到该定义

考虑Monster类中的代码:

def TakeDamage(self, amount, target:Hero):
damage = # damage calculation here
Hero.TakeDamage(damage)

(我暂时忽略了这里的逻辑可能没有那么大意义。)

编写:Hero是一个提示——对阅读代码的人来说,可能对第三方工具来说;Python本身并不关心-target将是Hero类的实例。

我们想在该实例上调用一个方法,而不是在类上调用。类没有TakeDamage方法;它只有一个TakeDamage函数,当我们通过实例查找它时,该函数用于创建方法

因此,代码应该而不是Hero.TakeDamage(damage)。应该是target.TakeDamage(damage),因为target是我们将调用其方法的Hero实例的名称。

为此,我们不需要Hero类的定义。monsters.py不应该import做任何事情来实现此功能。

当代码正在运行时,在尝试方法调用的那一刻,Python将检查名为target的东西是否具有TakeDamage属性。当它没有找到一个直接附加到实例的函数时,它会在类中查找,并在该类中找到TakeDamage函数。它将自动从中创建一个方法。然后,它将检查从这个过程中获得的TakeDamage是否是可调用的(剧透:它是,因为它是一个方法),并调用它。

以下是我设计这款游戏的方法:

├── backend
│   ├── __init__.py
│   ├── character.py
│   ├── heros.py
│   └── monsters.py
└── main.py

character.py是英雄和怪物之间的通用类。

# character.py
class Character:
def __init__(self):
self.health = 100
def attack(self, target):
target.take_damage(1)
def take_damage(self, amount):
self.health -= amount
def __repr__(self):
return (
f"{self.__class__.__name__}("
f"health={self.health!r}"
f")"
)
# heros.py
from .character import Character
class Hero(Character):
pass
# monsters.py
from .character import Character
class Monster(Character):
def attack(self, target):
target.take_damage(5)
# main.py
from backend.heros import Hero
from backend.monsters import Monster
h = Hero()
m = Monster()
h.attack(m)
m.attack(h)
print(h)
print(m)

输出:

Hero(health=95)
Monster(health=99)

这里的关键是发生在attack方法内部:它用amount调用target.take_damage()

注意,heros.py不导入monsters.py,反之亦然。这样做可能会导致循环引用,这很混乱。

相关内容

  • 没有找到相关文章

最新更新