简体   繁体   English

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

[英]When should I use 'assert' in Python?

For some context, I am making a Roguelike game in Python using the Doyren library (libtcod). 在某些情况下,我使用Doyren库(libtcod)在Python中制作Roguelike游戏。 I am more used to C++ where objects are strongly typed. 我更习惯于C ++,其中对象是强类型的。

I'm writing several classes, such as a GameMap, GameObject, etc. Many of these classes contain methods which expect certain types, for example: 我正在写几个类,比如GameMap,GameObject等。这些类中的许多都包含期望某些类型的方法,例如:

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

This method adds the GameObject game_object to the coordinate (x, y) on the map. 此方法将GameObject game_object添加到地图上的坐标(x,y)。 There are clearly several ways this function can be misused: 显然有几种方法可以滥用此功能:

  • A non-GameObject could be passed as game_object 非GameObject可以作为game_object传递
  • A non-integer could be passed as x or y 非整数可以作为x或y传递
  • A negative integer could be passed as x or y 负整数可以作为x或y传递
  • An integer that is beyond the map's width could be passed as x 超出地图宽度的整数可以作为x传递
  • An integer that is beyond the map's height could be passed as y 超出地图高度的整数可以作为y传递

My question is this: What is the Pythonic way to handle method misuse? 我的问题是: 处理方法滥用的Pythonic方法什么?

I see several possibilities: 我看到了几种可能性:

Option 1: Lay out a series of assertions at the start of the method: 选项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)
    ...

These assertions get fairly repetitive as I copy+paste them into many of my methods in GameMap, which is why I also provide option 2: 这些断言相当重复,因为我将它们复制并粘贴到GameMap中的许多方法中,这也是我提供选项2的原因:

Option 2: Write assertions in their own functions, and call those when needed to prevent copy+pasting 选项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)
    ...

Option 3: Lay out a series of custom exceptions at the start of the method: 选项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)
    ...

Option 4: Return failure indicator, and handle the issue at a higher level 选项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
    ...

Option X: Something else? 选项X:还有别的吗?

Any advice here would be greatly appreciated! 这里的任何建议将不胜感激! I want to make sure I'm following a useful and maintainable pattern as I go on. 我想确保我继续使用有用且可维护的模式。

The assertion is to make sure that objects, results, return, etc are what we expect them to be. 断言是为了确保对象,结果,返回等是我们期望的。 Though they can be used for variable's type checking, that's not what their real purpose is and it gets repetitive. 虽然它们可以用于变量的类型检查,但这不是它们的真正目的,而是重复性的。

In your case, I would suggest to use python EAFP way of doing things. 在你的情况下,我建议使用python EAFP的做事方式。 Let the operation be performed on function input and catch the exception if it's not what is expected. 让操作在函数输入上执行,如果不符合预期,则捕获异常。 From Python glossary : Python词汇表

EAFP: Easier to ask for forgiveness than permission. EAFP:比许可更容易要求宽恕。 This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. 这种常见的Python编码风格假设存在有效的键或属性,并且如果假设被证明是错误则捕获异常。 This clean and fast style is characterized by the presence of many try and except statements. 这种干净和快速的风格的特点是存在许多try和except语句。 The technique contrasts with the LBYL(Look before you leap) style common to many other languages such as C. 该技术与许多其他语言(例如C)共有的LBYL(Look before you leap)风格形成鲜明对比。

A quick example: 一个简单的例子:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM