Python:类的"init"中的if-else;这样可行吗?

5 投票
2 回答
14325 浏览
提问于 2025-04-16 23:23

我也是一个刚开始学习编程的新手,正在看《Learn Python the Hard Way》,遇到了一些我不太明白的东西。

在这里我想说,虽然我很喜欢这个课程,但有一个不太好的副作用就是我对编程世界里的很多技术术语都不太理解。我花了两天才搞明白什么是“实例化”,现在我觉得我可能明白了一点,嘿嘿。所以希望我的问题没有被别人用更专业的方式问过,如果有的话,我为重复提问感到抱歉。

总之,我现在想做的是完成一个文字冒险游戏,使用类来描述每个房间。实际上,我是在把我以前的一个作品移植到这种更新的、更“面向对象”的方式中——把一个大约980行的函数调用程序转换过来。

之前我在每个函数里都有这些“房间”,用来检查你是否达成了某些游戏目标,然后给你描述房间的情况。举个例子:

def room_one():
    if "flashlight" in pack:
        print "You see an exit to the NORTH and a bear to the EAST."
    elif "flashlight" not in pack:
        print "It's too dark to see."

这个房间很无聊,但描述得很到位。所以在尝试用类来实现这个功能时,我似乎遇到了瓶颈。我会给你看我用来定义游戏“运行者”和房间类的代码。

class Runner(object):
    def __init___(self):
        self.goals = [] #an array for game achievements (talked_to_king, etc)
        self.pack = [] #an array for game items (flask, key, etc)

    def play(self, currentroom, gamestate):

        while True:

            print "\n--------"
            print currentroom.desc #this line prints the room description, could
            cmd = raw_input("> ")  #it also be part of the problem?
            gamestate.state = currentroom.actions(cmd)

            if gamestate.state != "SAME":
                currentroom = gamestate.state

            else:
                pass

class Room(object):
    def __init__(self):
        self.desc = "null" #short room description
        self.lookdesc = "super null" #longer room description for the LOOK command


    def actions(self, cmd):
        if 'help' in cmd:
            print """
            'look' -- see your surroundings, including exits.
            'get' -- to pick up an item (if it can be picked up).
            'inventory' -- displays your collected items
            'throw' -- some objects can be thrown
            'talk' -- speak to someone
            Other commands, or objects to interact with, will tend to
            show up IN UPPERCASE. (but still type them in lowercase!)
            Cardinal directions (north, south, east, west) for movement.
            """
            return "SAME"
        elif 'inv' in cmd:
            print "--Inventory--\n"
            for items in game.pack:
                print items
            print "-------------\n"
            return "SAME"
        elif 'look' in cmd:
            print self.lookdesc
            return "SAME"
        elif 'goals' in cmd:
            for goal in game.goals:
                print goal
            return "SAME"
        else:
            print "That won't work here."
            return "SAME"


class Office(Room):

    def __init__(self):

        super(Office, self).__init__()
        # here's the part that doesn't work
        if 'principal' in game.goals:
            self.desc = "You're in the principal's office, and there's a zombie in here!"
        else:
            self.desc = "You're in the principal's office."

        self.lookdesc = "The walls in here are dingy from decades of smoking.\nA door to the WEST leads back to the foyer."



    def actions(self, cmd):

        if "west" in cmd and not "principal" in game.goals:

            print "Buck up and talk to the old prune."

            return "SAME"

        elif "talk" in cmd:

            print "You call to the principal."
            game.goals.append('principal')
            next = raw_input("--Mr. Friiiiinkseseeees...--")
            print "But OH MY DAMN he's actually a zombie now."
            next = raw_input("--Aww weak--")
            return "SAME"

        return super(Office, self).actions(cmd)

为了检查“目标”数组是否被添加,我在房间的父类里放了一个简单的目标检查函数,结果发现game.goals确实被添加了。但是我的if-else语句似乎没有实际效果;无论目标数组里有什么,我每次回到房间时总是得到else的描述。

公平地说,把if-else放在房间初始化里有点像是瞎猜,实际上我很惊讶没有收到错误信息告诉我这不是放这些的地方!但是,既然它似乎不关心game.goals数组的内容,这让我觉得这样做不是最好的方法。我应该怎么实现这个呢?

作为一个附加问题——在这样的程序里,如果游戏状态变化得很大,以至于房间的内容发生了剧烈变化,是不是更好为这个改变后的房间创建一个新的类?是更重要保持“地图”,让RoomThree(Room)始终是RoomThree,不管游戏状态发生了什么变化,还是说如果游戏回到RoomThree时,这个地方已经被破坏、被洗劫、着火、满是吸血鬼并且散发着生菜的味道,那是不是应该完全是一个不同的RoomThree?我有点希望不是,因为我觉得每个房间就“应该是那个房间”,让像game.goals和game.pack这样的内容改变类的实例,而不是为了某些条件创建一个新的类。

总之,我说得有点长。总结一下——我这样做是不是有点奇怪??

再次编辑:我清理了主要问题的代码,以符合这里人们建议的新代码,也添加了父类“Room”,看看这是不是问题的一部分。还是没有解决方案,但我相信代码的质量有所提高 :) 呜呼

最后一次编辑(我希望):啊哈,Stone的回答再次非常有帮助。因为我返回的是“same”给我的运行者,它使用的是旧的Office实例。我需要创建一个全新的实例来让它识别变化;通过返回“Office()”而不是“SAME”,我实现了这个。感谢大家不仅帮助我解决了当前的问题,还让代码更易读,并帮助我改变了对冗长的if-else语句的思考。亲亲 :D

2 个回答

-1

我想你是想说这个:

    if not 'principal' in game.goals:

或者是这个:

    if 'principal' not in game.goals:

或者这个:

    if not ('principal' in game.goals):

not 'somestring' 的结果是 False,因为非空字符串总是被认为是 True,而你的目标中没有 False,所以它总是会评估为 False


那Office对象是在哪里创建的呢?因为你只是检查对象创建时的条件,而主对象是在之后添加到目标中的,所以如果你再次使用同一个对象,描述是不会改变的。

1

如果你有100个房间,那你的游戏功能是不是得写100个if语句,来设置你所在的房间?(基本上就是再设置一次)

其实,直接在状态变化时把游戏状态设置成你想要的样子,可能会更好。

补充:我刚刚重新看了一下你的代码,现在问题看起来很明显,除非你漏掉了重要的代码。

你似乎只在Office这个类的成员函数里把“本金”加到“目标”里。因此,当你准备把本金加到目标时,已经太晚了,Office已经被初始化了,除非你创建一个新的Office实例,否则它不会再初始化。你需要在添加目标后更新房间的描述。

撰写回答