Issue
I'm trying to make a text-based RPG. I have some code like:
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):
# ...
The whole file structure looks like this:
|__ backend
__init__.py
monsters.py
heroes.py
MainGame.py
Let's say I want Monster
and Hero
to access each other's Attack
and TakeDamage
functions, for example:
class Monster():
def __init__(self):
pass
def Attack(self, target):
# ...
def TakeDamage(self, amount, target:Hero):
damage = # damage calculation here
target.TakeDamage(damage)
How can I do this? So far I've tried:
- Importing each other (e.g.
from .monsters import Monster
) in their respective files - this gives me an error readingImportError: cannot import name 'Monster' from partially initialized module 'backend.monsters' (most likely due to a circular import)
.
Solution
Broadly speaking, classes don't have methods; instances do. The purpose of a class is to define a data type. You don't need to see that definition, in Python, in order to use instances.
Consider the code in the Monster
class:
def TakeDamage(self, amount, target:Hero):
damage = # damage calculation here
Hero.TakeDamage(damage)
(I will ignore for the moment that the logic here probably doesn't make that much sense.)
Writing :Hero
is a hint - to the person reading the code, and possibly to third-party tools; Python itself does not care - that target
will be an instance of the Hero
class.
We want to call a method on that instance, not on the class. The class doesn't have a TakeDamage
method; it only has a TakeDamage
function, which is used to create the method when we look it up via an instance.
Therefore, the code should not say Hero.TakeDamage(damage)
. It should say target.TakeDamage(damage)
, because target
is the name of the Hero
instance whose method we will call.
To do this, we do not require the definition of the Hero
class. monsters.py
should not import
anything to make this work.
When the code is running, at the moment that the method call is attempted, Python will check whether the thing that is named target
has a TakeDamage
attribute. When it doesn't find one directly attached to the instance, it will look in the class, and find the TakeDamage
function in that class. It will automatically create a method from that. Then it will check that the TakeDamage
that it got from this process is callable (spoiler: it is, because it's a method), and call it.
Answered By - Karl Knechtel Answer Checked By - Candace Johnson (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.