在某些情况下,我使用Doyren库(libtcod)在Python中制作Roguelike游戏。我更习惯于C ++,其中对象是强类型的。
我正在写几个类,比如GameMap,GameObject等。这些类中的许多都包含期望某些类型的方法,例如:
class GameMap:
...
def add_object(self, game_object, x, y):
...
此方法将GameObject game_object添加到地图上的坐标(x,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)
...
选项4:返回失败指示符,并在更高级别处理问题
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:还有别的吗?
这里的任何建议将不胜感激!我想确保我继续使用有用且可维护的模式。
答案 0 :(得分:2)
断言是为了确保对象,结果,返回等是预期的。虽然它们可以用于对变量进行类型检查,但这并不是它们的真正目的,它们会重复出现。
在你的情况下,我建议使用python EAFP的做事方式。让操作在函数输入上执行,如果它不是预期的,则捕获异常。来自Python glossary:
EAFP:比获得许可更容易请求宽恕。这个常见的Python 编码风格假定存在有效的键或属性 如果假设被证明是假的,则捕获异常。这干净又快 风格的特点是存在许多尝试和除外 声明。该技术与许多人共同的LBYL(Look before you leap)风格形成鲜明对比 其他语言,如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