Python: 在 __init__ 中的字典中列出方法
Python: Listing methods in a dict in __init__
所以我想做的事情有点难以在标题中描述。
这是我想要做的:
在下面的代码中,我想要一些通用的方法,有人可以在 Room class(例如 Search、Loot)和 Player class(例如 quit、heal)上调用。我希望发生这种情况的方式是玩家在输入中输入他们想做的事情,然后 python 将在一个将选择与方法匹配的字典中查找该选择。
我已经通过房间的出口成功完成了这项工作。我可能可以通过制作 child class 并在其中列出方法来做到这一点,但我真的不想这样做,因为那样看起来很混乱。
当我运行下面的代码时,它会自动退出。如果我 运行 注释掉了第一个字典,我会收到一条错误消息,指出 __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
一种方法是
class Player(object):
actions = {
'QUIT': 'quit'
}
然后
def roomactivity(self):
while True:
[...]
elif choice in player.actions:
getattr(player, player.actions[choice])()
我发现了一些潜在的问题:
玩家actions
字典中的quit
来自哪里?它显示为某种已知名称 (variable/method/object),但您唯一一次将 quit 定义为 Player 的方法,因此 class 属性 actions
无法访问它。
quit 从未真正被调用过。例如,当 player.actions[choice]
在用户输入 "QUIT" 上执行时,即使 quit
确实存在,也只是 return 它指向的任何函数。它不会调用那个函数。这是不好的。 player.actions[choice]()
会让你到达那里。
在脚本中定义变量并在 class 中引用脚本变量是 no-no。让你的 class 方法调用 VoidRoom() 或 TestRoom() 是可以的,但是让它从完全不同的命名空间引用变量 test_room
和 void_room
,就没那么多了。
请参阅以下示例:
actions = {
'QUIT': quit
}
这不会退出您的程序。 "quit" 也是 python IDLE 中的保留字,因此不是方法的最佳选择。 Python 惯例是在末尾放一个'_'以避免与保留字冲突:quit_
。我会完全删除该属性并将其设为 属性,这样您就可以在其子项中覆盖它并添加额外的功能。您牺牲了使用自定义操作来初始化玩家的能力,但是如果 class 带有相关操作,这些不是更有意义吗?
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_room
和 test_room
,这很好。唯一的问题是你的 classes 对你的 运行 时间变量一无所知,所以如果你想要 North,South,East 和 West 映射到 VoidRoom 的实例(这是一个 class TestRoom 知道,因为它在模块中就位于它的上方),只需直接引用 VoidRoom(),而不是 void_room。永远不要假设您的 class 对 发生在 class 之外的任何事情 都一无所知,并且还没有传递到 class 的 __init__
=].
我希望带有动作 属性 的播放器示例(在这种情况下,只需将 属性 视为一种将函数作为变量引用的方式 - 因为动作 return 是 dict
,我们可以像 dict
一样对待它,而无需使用 actions() 调用方法。player.actions
将 return 字典,漂亮且可读)是有道理的,因为如果你以这种方式实现它,您可以拥有特定类型的吟游诗人,它们向下继承许多层,并且通过调用 super().actions
(它们的父级 class)覆盖操作意味着即使是最具体的 DwarfBlacksmithWhoSingsInHisSpareTime class一直获取所有父动作(因为每个动作方法都调用其父动作,一直调用直到它击中 Player),所以你得到一个可以戒烟、唱歌和打铁的矮人。非常优雅,我希望它不会太混乱,因为这是一个非常酷的概念。祝你好运!
所以我想做的事情有点难以在标题中描述。
这是我想要做的: 在下面的代码中,我想要一些通用的方法,有人可以在 Room class(例如 Search、Loot)和 Player class(例如 quit、heal)上调用。我希望发生这种情况的方式是玩家在输入中输入他们想做的事情,然后 python 将在一个将选择与方法匹配的字典中查找该选择。
我已经通过房间的出口成功完成了这项工作。我可能可以通过制作 child class 并在其中列出方法来做到这一点,但我真的不想这样做,因为那样看起来很混乱。
当我运行下面的代码时,它会自动退出。如果我 运行 注释掉了第一个字典,我会收到一条错误消息,指出 __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
一种方法是
class Player(object):
actions = {
'QUIT': 'quit'
}
然后
def roomactivity(self):
while True:
[...]
elif choice in player.actions:
getattr(player, player.actions[choice])()
我发现了一些潜在的问题:
玩家
actions
字典中的quit
来自哪里?它显示为某种已知名称 (variable/method/object),但您唯一一次将 quit 定义为 Player 的方法,因此 class 属性actions
无法访问它。quit 从未真正被调用过。例如,当
player.actions[choice]
在用户输入 "QUIT" 上执行时,即使quit
确实存在,也只是 return 它指向的任何函数。它不会调用那个函数。这是不好的。player.actions[choice]()
会让你到达那里。在脚本中定义变量并在 class 中引用脚本变量是 no-no。让你的 class 方法调用 VoidRoom() 或 TestRoom() 是可以的,但是让它从完全不同的命名空间引用变量
test_room
和void_room
,就没那么多了。
请参阅以下示例:
actions = {
'QUIT': quit
}
这不会退出您的程序。 "quit" 也是 python IDLE 中的保留字,因此不是方法的最佳选择。 Python 惯例是在末尾放一个'_'以避免与保留字冲突:quit_
。我会完全删除该属性并将其设为 属性,这样您就可以在其子项中覆盖它并添加额外的功能。您牺牲了使用自定义操作来初始化玩家的能力,但是如果 class 带有相关操作,这些不是更有意义吗?
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_room
和 test_room
,这很好。唯一的问题是你的 classes 对你的 运行 时间变量一无所知,所以如果你想要 North,South,East 和 West 映射到 VoidRoom 的实例(这是一个 class TestRoom 知道,因为它在模块中就位于它的上方),只需直接引用 VoidRoom(),而不是 void_room。永远不要假设您的 class 对 发生在 class 之外的任何事情 都一无所知,并且还没有传递到 class 的 __init__
=].
我希望带有动作 属性 的播放器示例(在这种情况下,只需将 属性 视为一种将函数作为变量引用的方式 - 因为动作 return 是 dict
,我们可以像 dict
一样对待它,而无需使用 actions() 调用方法。player.actions
将 return 字典,漂亮且可读)是有道理的,因为如果你以这种方式实现它,您可以拥有特定类型的吟游诗人,它们向下继承许多层,并且通过调用 super().actions
(它们的父级 class)覆盖操作意味着即使是最具体的 DwarfBlacksmithWhoSingsInHisSpareTime class一直获取所有父动作(因为每个动作方法都调用其父动作,一直调用直到它击中 Player),所以你得到一个可以戒烟、唱歌和打铁的矮人。非常优雅,我希望它不会太混乱,因为这是一个非常酷的概念。祝你好运!