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

时间:2017-10-13 06:13:21

标签: 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添加到地图上的坐标(x,y)。显然有几种方法可以滥用这个功能:

  • 非GameObject可以作为game_object传递
  • 非整数可以作为x或y
  • 传递
  • 负整数可以作为x或y
  • 传递
  • 超出地图宽度的整数可以作为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:还有别的吗?

这里的任何建议将不胜感激!我想确保我继续使用有用且可维护的模式。

1 个答案:

答案 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