在某些情况下,我正在使用 Doyren 库 (libtcod) 在 Python 中制作 Roguelike 游戏。我更习惯于强类型对象的 C++。
我正在编写几个类,例如 GameMap、GameObject 等。其中许多类包含需要特定类型的方法,例如:
class GameMap:
...
def add_object(self, game_object, x, y):
...
此方法将 GameObject game_object 添加到 map 上的坐标 (x, y)。显然有几种方法可以滥用此功能:
- 非 GameObject 可以作为 game_object 传递
- 非整数可以作为 x 或 y 传递
- 负整数可以作为 x 或 y 传递
- 可以将超出 map 宽度的整数作为 x 传递
- 可以将超出 map 高度的整数作为 y 传递
我的问题是:处理方法滥用的 Pythonic 方式是什么?
我看到了几种可能性:
选项 1:在方法的开头布置一系列断言:
def add_object(self, game_object, x, y):
assert(isinstance(game_object, GameObject)
assert(type(x) == type(y) == int)
assert(0 <= x < self.map_width and 0 <= y < self.map_height)
...
这些断言变得相当重复,因为我将它们复制并粘贴到我在 GameMap 中的许多方法中,这就是我还提供选项 2 的原因:
选项 2:在自己的函数中编写断言,并在需要时调用它们以防止复制+粘贴
def check_game_object(self, game_object):
assert(isinstance(game_object, GameObject)
def check_coordinate(self, x, y):
assert(type(x) == type(y) == int)
assert(0 <= x < self.map_width and 0 <= y < self.map_height)
def add_object(self, game_object, x, y):
check_game_object(game_object)
check_coordinate(x, y)
...
选项 3:在方法的开头布置一系列自定义异常:
def add_object(self, game_object, x, y):
if not isinstance(game_object, GameObject):
raise InvalidParameterException("game_object not a GameObject")
elif not type(x) == type(y) == int:
raise InvalidParameterException("(x, y) not integers")
elif not (0 <= x < self.map_width and 0 <= y < map.self_height)
raise InvalidMapCell("x, y do not represent a valid map cell)
...
方案四:返回失败指示器,并在更高级别处理问题
def add_object(self, game_object, x, y):
if not isinstance(game_object, GameObject):
return False
elif not type(x) == type(y) == int:
return False
elif not (0 <= x < self.map_width and 0 <= y < map.self_height)
return False
...
选项 X:还有别的吗?
如有任何建议,我们将不胜感激!我想确保我在继续时遵循一个有用且可维护的模式。
最佳答案
断言是为了确保对象、结果、返回等是我们所期望的。虽然它们可以用于变量的类型检查,但这并不是它们的真正目的,而且它会重复。
在你的情况下,我会建议使用 python EAFP 做事的方式。让操作在函数输入上执行,如果不是预期的,则捕获异常。来自 Python glossary :
EAFP: Easier to ask for forgiveness than permission. This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements. The technique contrasts with the LBYL(Look before you leap) style common to many other languages such as C.
一个简单的例子:
def f(x):
"""If x is str a TypeError is raised"""
return 1 + x
try:
f('a')
except TypeError as e:
# something here or raise a custom exception
raise
关于python - 什么时候应该在 Python 中使用 'assert'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46723564/