我什么时候应该在 Python 中使用 'assert'?

When should I use 'assert' in Python?

在某些情况下,我正在 Python 使用 Doyren 库 (libtcod) 制作 Roguelike 游戏。我更习惯于对象强类型化的 C++。

我正在编写几个 类,例如 GameMap、GameObject 等。其中许多 类 包含需要特定类型的方法,例如:

class GameMap:
    ...
    def add_object(self, game_object, x, y):
        ...

此方法将游戏对象 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:Return故障指标,上级处理

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:还有别的吗?

如有任何建议,我们将不胜感激!我想确保我在继续时遵循一个有用且可维护的模式。

断言是为了确保对象、结果、return等是我们所期望的。虽然它们可以用于变量的类型检查,但这并不是它们的真正目的,而且它会重复。

对于您的情况,我建议使用 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