我正在尝试重构一些旧代码,这些代码来自我在大学学习的初级CS课程
我注意到自那以后python发生了很多变化(2017(
我也找不到任何关于用python编写和使用抽象基类的信息丰富的在线教程(除了文档(,所以我对编写和使用ABC的正确方法没有什么可做的。
目前我有两个问题,一个更明确:
Traceback (most recent call last):
File "Hero.py", line 10, in <module>
from Enemy import Enemy
File "C:UsersBenvscodeSCMCS171AssignmentsZelda_CLI_gameEnemy.py", line 15, in <module>
class Enemy(metaclass = abc.ABCMeta):
File "C:UsersBenvscodeSCMCS171AssignmentsZelda_CLI_gameEnemy.py", line 32, in Enemy
def __init__(self):
AttributeError: 'function' object has no attribute '__bases__'
当我尝试运行"Hero.py"脚本时会出现
from Enemy import Enemy
class Hero(Enemy):
'''Class Level Docstring: Hero Object has six attributes,
most of which are nessecary for gameplay mechanisms.
Name is purely descriptive (no impact on game implementation details)
Therefore, name is the only mutable value, able to be set via constructor.
'''
def __init__(self,name):
self._name = name
self.__health = 200
self.__defense_mode = False
self.__bombs = 20
self.__elixers = 5
self.__arrows = 10
def __repr__(self):
'''Returns Hero attributes.
(health and defense_mode are implementation details)'''
return "Health: {} / 200n
rrBombs: {} / 20n
rrElixers: {} / 6n
rrArrows: {} / 10".format(self.__health, self.__bombs, self.__elixer, self.__arrows)
def __str__(self):
'''Returns Hero description'''
return "{}, a young warrior, clad in green".format(self.__name)
def health_bar(self):
'''Returns Hero health points vs. max health points.'''
return "{}/200".format(self.__health)
###Basic. Defense and Special attack for hero, overriden from Enemy.
def basic_attack(self, enemy):
'''Offensive attack that leaves Hero vulnerable.'''
self.__defense_mode = False
enemy.do_Damage(50)
def basic_name(self):
'''Provides name for Hero basic attack.'''
return "used the Master sword"
def defense_attack(self, enemy):
'''Parry attack that bolsters hero defense
while also doing small amount of damage to enemy.'''
self.__defense_mode = True
enemy.do_Damage(20)
def defense_name(self):
'''Returns the name for Hero defense attack'''
return "shield strike"
def special_attack(self, enemy):
'''A Powerful attack that does higher amount of damage
and also swaps defense mode. If defense mode is true,
does the standard amount of damage. If false, does
greater damage but also hurts the Hero.
'''
if self.__bombs:
if self.__defense_mode:
self.__defense_mode = False
enemy.do_damage(75)
return "The bomb had a Direct Hit.nYour enemy recoils"
else:
self.__defense_mode = True
enemy.do_damage(110)
self.__health -= 20
return "The bomb was very powerful.n
Your enemy was badly injured,n
but you were damaged as well by the shrapnel"
else:
return "no bombs remaining.nCannot use Special attack."
def special_name(self):
'''Returns the name of the special attack.'''
return "Used a bomb"
#Hero unique moves- Arrow and Elixer
def use_arrow(self, enemy):
'''Projectile attack:
highly effective, has no effect on defense mode.
but limited availability/ uses- 10 available arrows per game.'''
enemy.do_Damage(95)
self.__arrows= self.__arrows - 1
def arrow_name(self):
'''Returns the name of arrow attack.'''
return "{} fired an arrow".format(self.__name)
def arrow_count(self):
'''Returns the number of arrows remaining vs. maximum.'''
return "{} / 10".format(self.__arrows)
def elixer(self):
'''Replenishes half of the Heros max health point.
but limited uses, also turns defense mode to false.
'''
self.__defense_mode = False
self.__health + 100
self.__elixers - 1
def elixer_name(self):
'''Returns the name of the elixer move.'''
return "drank an elixer"
def elixer_count(self):
'''Returns the amount of remaining elixers vs max elixers.'''
return "{} / 5".format(self.__elixers)
def do_damage(self, damage):
'''
subtracts damage argument from Hero health.
If Defense mode is true, cuts value of damage argument in half.
'''
if(self.__defense_Mode):
self.__health -= damage // 2
else:
self.__health -= damage
def reset_health(self):
'''Sets the health points of Hero to maximum.'''
self.__health = 200
def reset_ammo(self):
'''Sets all the ammunititions to the max/initial value'''
self.__arrows = 10
self.__elixers = 5
if __name__ == "__main__":
print("Running in standby mode")
这是敌人抽象基类
import abc
from abc import ABCMeta
#cant figure out how to inherit from metaclass = ABCe
class Enemy(metaclass = abc.ABCMeta):
'''Class Level Docstring: creates signitures/ abstract methods
for init (constructor), __str__ (string repr.) and all helper
methods for gameplay.
NOTE: getter methods are retained from version 1, despite
this class adhering to the Descriptor protocol/ being a
new style class.
This is done in order to facilitate documentation.
When users implement the enemy class they will understand
how use of their object attributes makes gameplay/ battle possible.
'''
version = 2.0
@abc._abc_init
def __init__(self):
'''Construct enemy by passing in name, desc & health as args.'''
pass
@abc.abstractmethod
def __str__(self):
'''Returns all attributes/properties of the enemy.'''
return NotImplemented
@property
@abc.abstractmethod
def get_name(self):
'''Returns the enemy name.'''
return NotImplemented
@property
@abc.abstractmethod
def get_description(self):
'''Returns a short message describing
the enemy and providing any nessecary information.
'''
return NotImplemented
@property
@abc.abstractmethod
def get_health(self):
'''An enemy with 0 health is defeated.'''
return NotImplemented
#gamified versions of setters/mutator methods
@abc.abstractmethod
def do_damage(self, damage):
'''Positive numeric argument does damage,
and negative numeric argument heals enemy.'''
return NotImplemented
@abc.abstractmethod
def reset_health(self):
'''Returns health to starting HP.'''
return NotImplemented
# the attacks include: basic attack, defensive attack, special attack
# each of these has a corresponding method for returning the attack name.
@abc.abstractmethod
def basic_attack(self, enemy):
'''A less powerful, more commonly used attack.'''
return NotImplemented
@abc.abstractmethod
def basic_name(self):
'''returns basic attack name.'''
return NotImplemented
@abc.abstractmethod
def defense_attack(self, enemy):
'''Defensive move that counters or blocks an opponent
attack. some may infrequently do damage to opponent.
'''
return NotImplemented
@abc.abstractmethod
def defense_name(self):
'''Returns defense attack name.'''
return NotImplemented
@abc.abstractmethod
def special_attack(self, enemy):
'''Special attack which has limited availability, that may deal
extra damanage, have increased accurarcy, or some other desired effect.
'''
return NotImplemented
@abc.abstractmethod
def special_name(self):
'''Returns name of special attack,'''
return NotImplemented
另一个问题是intellisense或vscode在查找导入文件时遇到问题,尽管它们都在同一目录中。它强调了"敌人"在from Enemy import Enemy
中的首次出现
我的类名和包含该类的文件有相同的标题,这是问题吗
我提出了关于进口的第二个问题,因为我怀疑这可能是第一个错误的原因。这个导入行早些时候导致了错误,直到我编辑了我的首选项中的一些内容:python语言特定的配置文件(注释掉了"python.jediEnabled"这一行:false,因为用户遇到了类似问题,来自另一篇stackoverflow帖子的解决方案(。保存这些更改后,Hero.py和Enemy.py脚本立即工作,但在我开始得到上面提到的AttributeError之后不久。
我认为问题是
@abc._abc_init
在Enemy中的init函数上——你在哪里看到你需要这样做?一般来说,以下划线开头的东西被认为是私有的,从其他包导入时不应该使用。