【问题标题】:Python: Listing methods in a dict in __init__Python:在 __init__ 的字典中列出方法
【发布时间】:2018-02-25 01:45:47
【问题描述】:

所以我想做的事情有点难以在标题中描述。

这是我想做的: 在下面的代码中,我想要一些可以在 Room 类(例如 Search、Loot)和 Player 类(例如 quit、heal)上调用的通用方法。我希望发生这种情况的方式是玩家在输入中输入他们想要做的事情,python 将在 dict 中查找该选择,该选择与方法相匹配。

我已经通过房间的出口成功地做到了这一点。我可能可以通过创建一个子类并在其中列出方法来做到这一点,但我真的不想这样做,因为这看起来很混乱。

当我运行下面的代码时,它只是自动退出。如果我在第一个字典被注释掉的情况下运行它,我会收到一条错误消息,指出 __init__() 缺少必需的位置参数。

from textwrap import dedent
from sys import exit

class Player(object):


    actions = {
        'QUIT': quit
    }
    def __init__(self, actions):
        self.actions = actions
        # Want actions to be a list of actions like in the Room Class
        # 

    def quit(self):
        # Quits the game
        exit(0)

class Room(object):

    # Description is just a basic room description. No items needed to be added here.
    def __init__(self, desc, exits, exitdesc):
        self.desc = desc
        self.exits = exits
        self.exitdesc = exitdesc
        # Also want list of general actions for a room here.

    def enterroom(self):
        #First print the description of the room
        print(self.desc)
        #Then print the list of exits.
        if len(self.exits) > 1:
            print(f"You see the following exits:")
            for exd in self.exitdesc:
                print(self.exitdesc[exd])
        elif len(self.exits) == 1:
            print(f"There is one exit:")
            for exd in self.exitdesc:
                print(self.exitdesc[exd])
        else:
            print("There are no exits.")
        # Then allow the player to make a choice.
        self.roomactivity()

    # Here's what I mean about calling the methods via a dictionary
    def roomactivity(self):
        while True:
            print("What do you want to do?")
            choice = input("> ").upper()
            if choice in self.exits:
                self.exits[choice].enterroom()

    #And here's where I want to call actions other than directions.
            elif choice in player.actions:
                player.actions[choice]
            else:
                print("I don't understand.")

class VoidRoom(Room):
    def __init__(self):
        super().__init__(
            desc = "ONLY VOID.",
            exits = {},
            exitdesc = {})

class TestRoom(Room):
    def __init__(self):
        super().__init__(
            desc = dedent("""
                This room is only a test room.
                It has pure white walls and a pure white floor.
                Nothing is in it and you can hear faint echoes
                of some mad sounds."""),

            exitdesc = {
                'NORTH': 'To the NORTH is a black door.',
                'SOUTH': 'To the SOUTH is a high window.',
                'EAST': 'To the EAST is a red door.',
                'WEST': 'To the WEST is a blue door.'},
            exits = {
                'NORTH': void_room,
                'SOUTH': void_room,
                'EAST': void_room,
                'WEST': void_room})

void_room = VoidRoom()
test_room = TestRoom()
player = Player()

test_room.enterroom()

我希望我已经清楚地解释了这个问题。还在学习这门语言,我现在可能已经吃不消了。

编辑:下面的新代码:

我已经改变了一些东西,我将播放器命令和内容放在一个单独的 py 文件中,这样我就可以扩展播放器范围而不会弄乱 rooms.py 文件。

from textwrap import dedent
from sys import exit
from player import *
from enemies import *

# This is the base class for a room.
class Room(object):

    # Description is just a basic room description. No items needed to be added here.
    def __init__(self, desc, exits, exitdesc, inventory):
        self.desc = desc
        self.exits = exits
        self.exitdesc = exitdesc
        self.inventory = inventory

    def enterroom(self):
        #First print the description of the room
        Player.currentroom = self
        print(self.desc)
        for item in self.inventory:
            print(self.inventory[item].lootdesc)
        #Then print the list of exits.
        if len(self.exits) > 1:
            print(f"You see the following exits:")
            for exd in self.exitdesc:
                print(exd)
        elif len(self.exits) == 1:
            print(f"There is one exit:")
            for exd in self.exitdesc:
                print(exd)
        else:
            print("There are no exits.")
        # Then allow the player to make a choice.
        self.roomactivity()

    def roomactivity(self):
        while True:
            print("What do you want to do?")
            choice = input("> ").upper()
            if choice in self.exits:
                self.exits[choice]().enterroom()
            elif choice in Player.actions:
                Player.actions[choice]()
            else:
                print("I don't understand.")
                #Player.actions[choice]()

class Room3(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                You are in a large, dimly lit room.
                Torches sit in empty alcoves, giving off an eerie red glow.
                You hear scratching and squeaking from behind the walls."""),
            exits = {
                'NORTHEAST': StartRoom
            },
            exitdesc = [
                'A sturdy looking door leads to the NORTHEAST'
            ],
            inventory = {})



class Room1(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                You are in a medium sized, dimly lit room.
                Busts of dead men you don't know sit atop web-strewn pedestals."""),
            exits = {
                'EAST': StartRoom
            },
            exitdesc = [
                'An arch leading into a dimly lit hall lies to the EAST.'
            ],
            inventory = {'IRON SWORD': iron_sword}
        )



class StartRoom(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                PLACEHOLDER LINE 49"""),
            exits = {
                'SOUTHWEST': Room3,
                'WEST': Room1
            },
            exitdesc = [
                'An arch leading into a dimly lit room lies to the WEST',
                'A sturdy looking door lies to the SOUTHWEST'],
            inventory = {}
        )



class HelpPage(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                All actions will be listed in all caps
                When asked for input you may:
                QUIT the game
                Check your INVENTORY
                Check your player STATUS
                SEARCH the room
                EXAMINE an object or point of interest
                USE an item from your inventory or the room
                ATTACK a creature
                GET an item from the room
                or pick a direction (listed in caps)"""),
            exits = {},
            exitdesc = [
                'Press ENTER to return to the Main Menu'],
            inventory = []
            )

    def enterroom(self):
        print(self.desc)
        for exd in self.exitdesc:
            print(exd)
        self.roomactivity()

    def roomactivity(self):
        input()
        MainMenu.enterroom()

help_page = HelpPage()

# Main menu, lil bit different from a regular room
class MainMenu(Room):

    def __init__(self):
        super().__init__(
            desc = dedent("""
                THE DARK DUNGEON OF THE VAMPIRE KNIGHT
                A game by crashonthebeat"""),
            exits = {
                'START': StartRoom,
                'HELP': HelpPage
            },
            exitdesc = [
                'Press START to Start the Game',
                'Or go to the HELP Menu'],
            inventory = []
            )

        def enterroom(self):
            print(self.desc)
            for exd in self.exitdesc:
                print(exd)
            self.roomactivity()

        def roomactivity(self):
            while True:
                choice = input("Choose an Option: ")
                if choice in self.exits:
                    self.exits[choice]().enterroom()
                else:
                    print("I don't understand")

以及 player.py 中的相关代码

from items import *
from rooms import *

class Player(object):

    @property
    def actions(self):
        actions_map = {
            'QUIT': 'quit_',
            'STATUS': 'status',
            'INVENTORY': 'printinventory',
            'EXAMINE': 'examine',
            'USE': 'useitem',
            'SEARCH': 'searchroom',
            'GET': 'getitem',
            'CURRENTROOM': 'getcurrentroom'
        }
        return actions_map

【问题讨论】:

  • 我认为错误在于您正在制作类级别的变量操作。尝试制作 like` def init (self,input):` 然后在那个 self.actions = input 这可能会起作用。

标签: python text adventure


【解决方案1】:

我看到了一些潜在的问题:

  1. 玩家的actions 字典中的quit 来自哪里?它显示为某种已知名称(变量/方法/对象),但您定义的唯一一次退出是作为 Player 的方法,因此类属性 actions 无法访问它。

  2. quit 从未真正被调用过。例如,当player.actions[choice] 在用户输入“QUIT”上执行时,即使quit 确实存在,它也只会返回它指向的任何函数。它不会调用那个函数。这是不好的。 player.actions[choice]() 会带你到那里。

  3. 在您的脚本中定义一个变量并在您的类中引用该脚本变量是不允许的。可以让你的类方法调用 VoidRoom() 或 TestRoom(),但让它从完全不同的命名空间引用变量 test_roomvoid_room,而不是那么多。

请看下面的例子:

actions = {
        'QUIT': quit
    }

这不会退出您的程序。 “quit”也是python IDLE中的保留字,所以不是方法的最佳选择。 Python 约定是在末尾添加一个“_”以避免与保留字冲突:quit_。我将完全删除该属性并使其成为属性,因此您可以在其子项中覆盖它并添加额外的功能。您牺牲了使用自定义操作初始化玩家的能力,但是这些作为具有关联操作的类不是更有意义吗?

class Player(object):
    @property
    def actions(self):
        actions_map = {
            'QUIT': self.quit_
        }
        return actions_map

    def quit_(self):
        print("Quitting the game.")
        exit(0)

class PlayerThatCanSing(Player):
    @property
    def actions(self):
        default_actions = super().actions # We still want Player actions
        new_actions = {
            'SING': self.sing
        }
        combined_actions = new_actions.update(default_actions) # Now player can quit AND sing
        return combined_actions

    def sing(self):
        print("Do Re Ma Fa So La Te Do")

现在引用 player.actions['QUIT']() 调用 player.quit_,这就是你想要的。

关于#3:

class TestRoom(Room):
    def __init__(self):
        super().__init__(
            desc = dedent("""
                This room is only a test room.
                It has pure white walls and a pure white floor.
                Nothing is in it and you can hear faint echoes
                of some mad sounds."""),

            exitdesc = {
                'NORTH': 'To the NORTH is a black door.',
                'SOUTH': 'To the SOUTH is a high window.',
                'EAST': 'To the EAST is a red door.',
                'WEST': 'To the WEST is a blue door.'},
            exits = {
                'NORTH': void_room,
                'SOUTH': void_room,
                'EAST': void_room,
                'WEST': void_room})

void_room = VoidRoom()
test_room = TestRoom()
player = Player()

您在脚本运行时声明 void_roomtest_room,这很好。唯一的问题是您的类对您的运行时变量一无所知,因此如果您希望 North、South、East 和 West 映射到 VoidRoom 的实例(这是 TestRoom 知道的类,因为它就在上面它在模块中),只需直接引用 VoidRoom(),而不是 void_room。永远不要假设你的班级知道任何关于该班级之外发生的任何的事情,并且没有被传递到班级的__init__

我希望 Player 示例带有 actions 属性(在这种情况下,只需将属性视为将函数作为变量引用的一种方式 - 因为 actions 返回 dict,我们可以将其视为 dict 而无需用 actions() 调用方法。player.actions 将返回 dict,漂亮且可读)是有道理的,因为如果你以这种方式实现它,你可以拥有特定类型的吟游诗人,它们会向下继承许多层,并通过调用覆盖操作到super().actions(他们的父类)意味着即使是最具体的 DwarfBlacksmithWhoSingsInHisSpareTime 类也会一直向上获取所有父操作(因为每个操作方法都会调用它的父类,并且一直持续到它命中 Player),所以你得到了一个 Dwarf能戒烟、能唱歌、能打铁的人。相当优雅,我希望它不会太混乱,因为这是一个非常酷的概念。祝你好运!

【讨论】:

  • 老实说,不是 100% 确定您在第 1 点和第 3 点中的意思。我仍在努力掌握 OOP 中的描述性语言,所以我想了解您的意思'正在到达这里。我应该首先在哪里引用quit,以便它可以成为actions 的一部分?对于问题 3,有什么更好的方法来做到这一点?我只是 python 拉出输入中定义的键的条目,然后将其指向另一个房间。
  • 感谢您的进一步解释。这很有意义,并且使添加类变得不那么令人生畏。我现在唯一遇到的问题是,当我尝试调用退出操作或我添加的其他操作时,我得到了TypeError: 'method' object is not subscriptable。此外,您所说的在类中调用运行时变量是有道理的。我想有一种方法让它们在不调用变量的情况下工作,我收到了NameError: name 'StartRoom' is not defined 最后一个错误是我存在的祸根。
  • 您是否在您的操作方法上方添加了@property 装饰器?如果不是,则不能将其视为变量。如果说 StartRoom 未定义,则该类不知道 StartRoom。您是否在编写 StartRoom 类之前引用了 StartRoom?如果是这样,只需将 StartRoom 类剪切并粘贴到调用它的类上方。
  • 我设法修复了房间,我刚刚从 StartRoom 的末尾删除了()。但现在我收到一个错误,argument of type 'property' is not iterable. 我使用elif choice in Player.actions: 调用它,然后在它下面:Player.actions[choice]()
  • 您可以使用更新的代码进行编辑吗?我在您的原始代码中没有看到 StartRoom,删除 () 让我担心。
【解决方案2】:

一种方法是

class Player(object):


    actions = {
        'QUIT': 'quit'
    }

然后

def roomactivity(self):
    while True:
        [...]
        elif choice in player.actions:
            getattr(player, player.actions[choice])()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    • 2015-04-02
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多