Python - 在类函数之间传递变量不正确?

时间:2014-01-14 03:25:31

标签: python class pass-by-reference local-variables

该计划相当不言自明。我已经开始玩Python的基础知识,我真的迷失了这个。我习惯了C ++以及通过引用传递东西的奇妙能力。但是,在这里,我试图改变的类变量(Fighter.statHEALTH)不会改变,我读到它是因为整数是不可变的,它只是在本地创建一个新对象。那么我可以在世界上如何将更改应用于原始变量?我用谷歌搜索和谷歌搜索,但无济于事。我不想执行一些丑陋的操作,比如制作一个列表并传递它,如果我不需要的话。

#python 3.2.2

#   Create a small test project to have combat between two entities.    #
#   Combat should include 3 different stats: statATK, statDEF, and statHEALTH.  #
#   The two entities should be of the same class.   #

class Fighter:
    def __init__(self):
        self.statHEALTH = 10
        self.statATK = 3
        self.statDEF = 3

    def attack(self, enemyhealth):
        enemyhealth = (enemyhealth - self.statATK)
        return enemyhealth

    def defend(self):
        statDEF += 1


def main():
    James = Fighter()
    Keaton = Fighter()
    while James.statHEALTH > 0:
        print("Do you wish to attack or defend?")
        print("1. Attack")
        print("2. Defend")
        choice = input()
        if choice == "1":
            James.attack(Keaton.statHEALTH)
            print("You did", James.statATK, "damage!") 
            Keaton.attack(James.statHEALTH)
            print("Keaton has", Keaton.statHEALTH, "health left.")
            print("Keaton did", Keaton.statATK, "damage!")
            print("You have", James.statHEALTH, "health left.")
        #elif choice == "2":
            #James.defend()
            #Keaton.attack(James.statHEALTH)

main()

4 个答案:

答案 0 :(得分:3)

def attack(self, enemyhealth):
    enemyhealth = (enemyhealth - self.statATK)
    return enemyhealth

如果您将通话更改为

,这实际上会有效
Keaton.statHEALTH = James.attack(Keaton.statHEALTH)

..因为你return来自攻击造成的伤害。显然这很难看;重复自己并不好。相反,您可以使attack看起来像:

def attack(self, other):
    other.statHEALTH -= self.statATK

然后就这样做

James.attack(Keaton)

当你打电话时。

答案 1 :(得分:1)

也许你可以用不同的方式来思考它。在您的示例中,Fighter.attack()只会在攻击后返回敌人的健康值。所以,它应该是对敌人物体的方法调用。您可以添加一种方法,在受到攻击时降低战斗机的健康状况:

def attack(self, enemy):
    enemy.getAttacked(self.statATK)

def getAttacked(self, ATK):
    self.statHEALTH -= ATK

答案 2 :(得分:1)

尝试做:

while James.statHEALTH > 0:
    #print statements
    if choice == "1":
        the_attack = James.attack(Keaton)

然后将您的类定义为:

class Fighter(object):
    def __init__(self):
        self.statHEALTH = 10
        self.statATK = 3
        self.statDEF = 3

    def attack(self,target):
        attack_details = target.takedamage(self.statATK)
        return attack_details

    def takedamage(self,dmg):
        modified_dmg = dmg-self.statDEF
        self.statHEALTH -= modified_dmg
        return modified_dmg

这具有易于扩展的额外好处,例如,你可以为某些元素添加一个命中表(for i in random.randint(1,100) if i < 20: #miss; elif 20 <= i < 80: #hit; elif 80<= i: #crit)或阻力,或者添加一个标志,允许你的后卫在他们的takedamage函数中进行反击(可能会调用一个新函数getcountered来防止无限循环)。

答案 3 :(得分:1)

问题不在于您无法通过Python中的引用传递内容。实际上,您总是通过引用传递值;除非你要求,否则Python永远不会复制值。

或者更确切地说,整个基于C的术语在Python中具有误导性。

无论如何,当你这样做时:

James.attack(Keaton.statHEALTH)

这不会复制Keaton.statHEALTH中的值,它会将引用传递给完全相同的值。因此,当attack开始时,您的enemyhealth变量就是该值的名称。

然后你这样做:

enemyhealth = (enemyhealth - self.statATK)

... enemyhealth - self.statATK返回一个新值,然后将该新值绑定到enemyhealth名称。这对旧值的任何其他名称都没有影响。

有两种方法可以解决这个问题。


首先,你实际上并不需要需要来改变任何东西。你最后已经在做return enemyhealth了。这意味着调用者可以获得您计算的新值。那么为什么不用它?

Keaton.statHEALTH = James.attack(Keaton.statHEALTH)

然后一切正常。


当然在C ++中,您可以改变整数值。当你想到它时,这似乎有点傻 - 将数字24转换为数字19会破坏大量数学,并且可能使宇宙停止工作,而Python就不那么强大了。

但是你可以轻松地构建一个可以明显变异的类型。实际上,您已经构建了一个:Fighter保存整数运行状况值,但可以更改为保持不同的值。所以,你可以这样写:

def attack(self, enemy):
    enemy.health = enemy.health - self.statATK

然后:

James.attack(Keaton)

正如调用使用Keaton.health的旧方法将enemyhealth转换为对同一号码的另一个引用一样,使用Keaton调用新方法会使enemy成为对Fighter的引用相同enemy。如果您刚刚将新值重新分配给Keaton,则不会对旧值(Keaton引用的值)产生任何影响。但是,如果您就地更改了值,显然{{1}}仍然指的是现在更改的值。