gpt4 book ai didi

python - 有关从子类中提取对象信息的问题

转载 作者:太空宇宙 更新时间:2023-11-03 15:02:07 25 4
gpt4 key购买 nike

如果我有类似的问题,我深表歉意。我对python还不太熟悉,仍然习惯于oop。这就是说,如果这个群体中的许多善良的灵魂中有一个能够帮助我解决我的具体情况,或者把我引向已经被问到的类似问题的方向,尽管我想指出的是,google没有帮助,每个有类似错误的问题都有很大的不同,而且跨越了很多不同的项目,我很难找到解决办法——我将不胜感激。
假设我有一个名为“objects.py”的文件,用于存储我正在开发的基于文本的游戏的大部分类对象,在该文件中,我有一个名为“职业”的类。类“ocposition”保存用作“player”类修饰符的变量,稍后将对其进行更多描述。
其思想是,在根文件(即“root.py”)中,玩家将能够从玩家职业列表中进行选择,例如“巫师”或“骑士”,并使来自各个职业类的信息替换当前玩家变量信息。
“player.py”文件:

import objects

class Player(object):
nextlevel = 30
# 'nextlevel' is the gold required for a level up.
def __init__(self):
self.name = ''
self.level = 1
self.health = 1
self.stamina = 0
self.mana = 0
self.skills = {'str': 0, 'def': 0, 'dex': 0, 'int': 0, 'chr': 0, 'lck': 0}
self.spells = []
self.inventory = [{'armor': [objects.PrisonerRobes()], 'weapons': [objects.IronDagger()], 'bows': [], 'potions': [], 'misc': []}, objects.Gold(0), objects.Arrow(0)]
self.victory = False

“objects.py”文件:
class Occupation(object):
# Base class for all occupations / classes, e.g. 'knight' or 'wizard'.
classlist = ['warrior', 'knight', 'paladin', 'druid', 'warlock', 'wizard']
def __init__(self, name, hp, sp, mp, strv, defv, dexv, intv, chrv, lckv):
# The variable names of 'strv', 'defv', etc. stand for 'strength value', 'defence value', etc.
self.name = name
self.health = health
self.stamina = stamina
self.mana = mana
self.strv = strv #skill values
self.defv = defv
self.dexv = dexv
self.intv = intv
self.chrv = chrv
self.lckv = lckv

def __str__(self):
details = '{0}: HP: {1}, SP: {2}, MP: {3} // [STR: {4}, DEF: {5}, DEX: {6}, INT: {7}, CHR: {8}, LCK: {9}]'
return details.format(self.name, self.health, self.stamina, self.mana, self.strv, self.defv, self.dexv, self.intv, self.chrv, self.lckv)

class Warrior(Occupation):
def __init__(self):
super(Warrior, self).__init__('Warrior', 75, 50, 25, 12, 8, 12, 5, 8, 5)

“根.py”文件:
from player import Player
import objects

def new_game():
while True:
print 'Only one class, and it is Warrior!'
print objects.Warrior()
classchoice = raw_input('Please type the full name of the class you wish to select.: ').lower()
playerclass = classchoice.title()
if classchoice != '':
characterclass = getattr(objects, playerclass)
player.health = characterclass.health
player.stamina = characterclass.stamina
player.mana = characterclass.mana
player.skills['str'] = characterclass.strv
player.skills['def'] = characterclass.defv
player.skills['dex'] = characterclass.dexv
player.skills['int'] = characterclass.intv
player.skills['chr'] = characterclass.chrv
player.skills['lck'] = characterclass.lckv
print 'You have chosen {0} as your class.'.format(characterclass.name)
confirm = raw_input('Is this correct? Type [Y] or [N] for yes/no respectively.: ').lower()
if confirm == 'y':
break
elif confirm == 'n':
continue
else:
print 'Not a valid keystroke!'
continue

当选择玩家等级时,输入“战士”时出现问题。
line 48[in my original file]: player.health = characterclass.health
AttributeError: type object 'Warrior' has no attribute 'health'

当我试图更新预先存在的玩家值时,我似乎不能引用我想要的变量。据我所知,“战士”类具有变量“health”,但我似乎无法访问它。我是否误解了类和子类在python中的工作方式?还是别的什么?
谢谢你的帮助。

最佳答案

我不同意查尔斯·梅里亚姆的回答我喜欢不同的课程。是的,一开始他们看起来都很像,只是有不同的数据但稍后您可以扩展它们以容纳多个功能。例如特殊修饰语,如战士的“愤怒”或巫师的“冥想”。
如果您将所有的鸡蛋放在一个字符类中,并且只是将不同的类表示为字符类的一个字符串属性,那么您以后将无法进行扩展事实上,我在文章的最后添加了rage方法,看到了Charles Merriam的答案因为我使用了你的继承模型,所以我只需要修改这些行(原来我只想给你看作文。)
组成
在我展示这个继承的东西能做什么之前,我认为你做错了我认为您已经为您的职业创建了一个类继承模型,但后来迷失了方向,希望将其作为属性全部推送到Player类中。
更多的实际操作:你定义了一个职业类来保存属性(生命,法力,耐力,灵巧…)然后您创建了一个Player对象并使其完全相同,除了一些额外的Warrioritems属性。如果你花了所有这些努力来编码统计数据作为职业类的属性,你为什么要让玩家拥有特定的、独立的统计数据,就好像职业不存在一样?你不会的。
但具体怎么办我认为职业不能拥有物品。我们并没有像这样对职业进行编码,一个教学和思想体系拥有任何东西都有点奇怪。所以我想避免和球员一起继承职业。玩家不是职业的延伸,即使玩家可以拥有职业因此,我们想要的是一篇作文。
这时,您获取一个占领对象,并将其作为属性分配给一个玩家对象。

class CharClass(object):
#these stats have to be defined for EVERY occupation possible
#This can be used as a base class for players without defined classes yet
#by defining the default values of __init__
def __init__(self, name="Unknown", health=30, stamina=10, mana=10,
strv=1, defv=1, dexv=1, intv=0, chrv=0, lckv=0):
self.name = name
self.health = health
self.stamina = stamina
self.mana = mana
self.strv = strv #skill values
self.defv = defv
self.dexv = dexv
self.intv = intv
self.chrv = chrv
self.lckv = lckv

def __str__(self):
details = '{0}: HP: {1}, SP: {2}, MP: {3} \n'+\
'[STR: {4}, DEF: {5}, DEX: {6}, INT: {7}, CHR: {8}, LCK: {9}]'
return details.format(self.name, self.health, self.stamina, self.mana, self.strv,
self.defv, self.dexv, self.intv, self.chrv, self.lckv)


class Warrior(CharClass):
def __init__(self):
super(Warrior, self).__init__(health=100, stamina=50, dexv=20)

def __str__(self):
parentstring = super(Warrior, self).__str__()
return "You are a Warrior \n"+parentstring

class Player(object):
def __init__(self, charclass=CharClass(), items=[], spells=[], victory=False):
self.charclass = charclass #the generic class is the default one
self.items = items
self.spells = spells

现在我们使用了合成,您不必为每个玩家单独设置任何统计信息。这使得你的代码更短,可读性更强。您可以通过战士对象访问这些对象,这是您的玩家类的一个属性,如下所示:
newplayer = Player()
print newplayer
print newplayer.charclass

print

#graduating to a Warrior
newplayer.charclass = Warrior()
print newplayer
print newplayer.charclass

print

#there's a snag though. Every time now if you want to print or change Players health
#(or some other attribute) you'd have to spell all of this:

print newplayer.charclass.health
newplayer.charclass.health += 100
print newplayer.charclass.health

#this is because Player object contains a Warrior object in it and what you really change is that
#Warrior object and not the Player.

print type(newplayer.charclass)

上述代码的输出为:
<__main__.Player object at 0x000000000427A550>
Unknown: HP: 30, SP: 10, MP: 10
[STR: 1, DEF: 1, DEX: 1, INT: 0, CHR: 0, LCK: 0]

<__main__.Player object at 0x000000000427A550>
You are a Warrior
Unknown: HP: 100, SP: 50, MP: 10
[STR: 1, DEF: 1, DEX: 20, INT: 0, CHR: 0, LCK: 0]

100
200
<class '__main__.Warrior'>

无缝组合
有一个技巧/权宜之计来解决这个问题,尽管对新手来说要想得到它有点困难别担心,一个月后当世界变得更有意义的时候再回顾。
如果在预期的位置找不到属性,则调用特殊函数 victory__getattr__我们重写这些函数来截取特殊符号 __setattr__(即 .)和 self.attribute的作用。我们让这些操作符设置或获取player类的属性,而不是设置或获取合成对象的属性!
class Player(object):
def __init__(self, charclass=CharClass(), items=[], spells=[], victory=False):
self.charclass = charclass
self.items = items
self.spells = spells

def __getattr__(self, attr):
return getattr(self.charclass, attr)

def __setattr__(self, attr, val):
if "charclass" in vars(self) and attr in vars(self.charclass):
self.charclass.__dict__[attr] = val
else:
self.__dict__[attr] = val

有了这个功能,我们可以再次执行此操作(无需在任何地方编写 =
print newplayer.health
newplayer.health -= 50
print newplayer.health

输出为:
200
150

很难在没有错误的情况下使用 self.charclasscharclass。它们不是容易覆盖的函数。
使用 __getattr__更容易,只要player对象中没有同名的内容,它就会自动被调用。所以你要小心的是不要在player中添加同名的新属性。
但是当player对象还没有任何属性时, __setattr__函数中也会调用 __getattr__。如果我们不检查,我们会得到一个错误。这就是 __setattr__所做的;检查 __init__是否向对象添加了 if "charclass" in vars(self)属性。
但是如果我们只检查 __init__属性,当我们尝试添加另一个属性时会发生什么即第二排: charclasscharclass将被调用,它将检查 items中的 __setattr__,它将看到它在那里,然后它将添加项到 charclass而不是 self!实际上,它会将属性添加到战士对象而不是玩家对象。
那么我们如何向player对象添加新属性呢?答案是我们只设置已经存在的战士对象属性。战士中不存在的所有属性(SoC.Car类)都被设置为玩家实例的属性( self.charclass)。这就是 self的意思。
继承和组合有助于以后扩展代码
回到顶端,为什么我不同意查尔斯·梅里亚姆的回答现在,要对代码的功能进行扩展和更改,您只需向warrior类添加方法,例如,让我们添加 self.__dict__[attr] = valand attr in vars(self.charclass)方法:
class Warrior(CharClass):
#this class basically just defines different default values than CharClass
def __init__(self):
super(Warrior, self).__init__(health=100, stamina=50, dexv=20)

def __str__(self):
parentstring = super(Warrior, self).__str__()
return "You are a Warrior \n"+parentstring

def rageON(self):
print "You are in a blood-rage +30 attack modifier"
self.stamina += 30

def rageOFF(self):
print "You have calmed down."
self.stamina -= 30

他们将立即在你的球员类,而不需要你改变球员。
newplayer.rageON()
print newplayer.charclass
print "----------------------------------------------------------------------------------------"
newplayer.rageOFF()
print newplayer.charclass

输出:
You are in a blood-rage +30 attack modifier
You are a Warrior
Unknown: HP: 150, SP: 80, MP: 10
[STR: 1, DEF: 1, DEX: 20, INT: 0, CHR: 0, LCK: 0]
----------------------------------------------------------------------------------------
You have calmed down.
You are a Warrior
Unknown: HP: 150, SP: 50, MP: 10
[STR: 1, DEF: 1, DEX: 20, INT: 0, CHR: 0, LCK: 0]

如果你按照查尔斯的建议在player或character类中完成了这一切,那么你必须在player类中添加一个method rage。在里面你必须检查你是否真的是“勇士”,然后才能执行它。
在你意识到每一个你想要的类的特殊效果,你必须写一个这样的方法之前,这听起来并没有那么多的工作。它们都必须在一个单独的文件中定义Player类这听起来确实很糟糕。我不知道为什么我写了这些,但现在投入太多,不能不发表。对不起的。

关于python - 有关从子类中提取对象信息的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36756282/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com