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

标签 python python-3.x unit-testing testing assert

在某些情况下,我正在使用 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/

相关文章:

javascript - 错误: Mismatch in sampling rate: Expected: 16000; Actual: 48000. Tensorflow js抛出错误

javascript - 如何使用 jinja 将 null 从 python 传递给 javascript

mysql - Django 2.0 - 使用转储数据中的固定装置进行测试给出 utf8mb4 编码错误

c++ - 海龟模型 : MOCK_EXPECT fails if mocked class method returns a value

node.js - mock 鹅 : how to simulate a error in mongoose?

python - 类型错误 : 'module' object is not callable

python - 使用 .agg(许多列)保留 groupby 之后的所有列更有效

python - 如何使用 Python 3 打印 map 对象?

python - 我可以使用 WordPress 来支持 PyPI 文档页面吗?

c# - 为什么此单元测试在 Visual Studio 2005 中通过但在 VS2008 中失败?