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

Ash*_*ley 3 python testing unit-testing assert python-3.x

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

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

class GameMap:
    ...
    def add_object(self, game_object, x, y):
        ...
Run Code Online (Sandbox Code Playgroud)

此方法将GameObject game_object添加到地图上的坐标(x,y)。显然有几种方法可以滥用此功能:

  • 非GameObject可以作为game_object传递
  • 非整数可以作为x或y传递
  • 负整数可以作为x或y传递
  • 超出地图宽度的整数可以作为x传递
  • 超出地图高度的整数可以作为y传递

我的问题是:处理方法滥用的Python方法什么?

我看到几种可能性:

选项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)
    ...
Run Code Online (Sandbox Code Playgroud)

当我将它们复制并粘贴到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)
    ...
Run Code Online (Sandbox Code Playgroud)

选项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)
    ...
Run Code Online (Sandbox Code Playgroud)

选项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
    ...
Run Code Online (Sandbox Code Playgroud)

选项X:还有其他东西吗?

这里的任何建议将不胜感激!我想确保我在继续的过程中遵循一种有用且可维护的模式。

Ami*_*thi 5

断言是确保对象,结果,返回值等与我们期望的一样。尽管它们可以用于变量的类型检查,但这并不是它们的真正目的,并且它会重复。

在您的情况下,我建议使用python EAFP做事方式。让该操作在函数输入上执行,并在异常之外捕获异常。从Python词汇表

EAFP:要求宽恕比允许容易。这种通用的Python编码风格假设有效键或属性的存在,并且在假设被证明为假的情况下捕获异常。这种干净快捷的样式的特点是存在许多try和except语句。该技术与C等其他许多语言通用的LBYL(飞跃前看)风格形成鲜明对比。

一个简单的例子:

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
Run Code Online (Sandbox Code Playgroud)

  • @mazunki只是一个简单的例子 (2认同)