标签归档:assert

带有和不带括号的python断言

问题:带有和不带括号的python断言

这是assert的四个简单调用:

>>> assert 1==2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert 1==2, "hi"
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError: hi

>>> assert(1==2)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert(1==2, "hi")

请注意,最后一个不会引发错误。调用带或不带括号的assert导致此行为之间有什么区别?我的做法是使用括号,但以上内容表明我不应该这样做。

Here are four simple invocations of assert:

>>> assert 1==2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert 1==2, "hi"
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError: hi

>>> assert(1==2)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert(1==2, "hi")

Note that the last one does not raise an error. What is the difference between calling assert with or without parenthesis that causes this behavior? My practice is to use parenthesis, but the above suggests that I should not.


回答 0

如果您通过完整的解释程序而不是通过IDLE运行最后一个命令assert,则会给您一个警告(SyntaxWarning: assertion is always true, perhaps remove parentheses?)。因为assert是一个关键字而不是一个函数,所以实际上您将元组作为第一个参数传递而忽略了第二个参数。

回想一下,非空元组的计算结果为True,并且由于断言消息是可选的,因此您在assert True编写时实际上已经调用了assert(1==2, "hi")

The last assert would have given you a warning (SyntaxWarning: assertion is always true, perhaps remove parentheses?) if you ran it through a full interpreter, not through IDLE. Because assert is a keyword and not a function, you are actually passing in a tuple as the first argument and leaving off the second argument.

Recall that non-empty tuples evaluate to True, and since the assertion message is optional, you’ve essentially called assert True when you wrote assert(1==2, "hi").


回答 1

如果因为需要多行断言而将括号放在此处,则另一种方法是在行的末尾添加反斜杠,如下所示:

foo = 7
assert foo == 8, \
    "derp should be 8, it is " + str(foo)

印刷品:

AssertionError: "derp should be 8, it is 7

为什么此python assert必须与其他所有东西都不同:

我认为python的思想是程序应该自行更正,而不必担心打开断言的特殊标志。关闭断言的诱惑太大,因此已被弃用。

令我烦恼的是,assert相对于所有其他python编程构造,python 具有唯一的语法,并且此语法再次从python2更改为python3,又从python 3.4更改为3.6。使断言语句从任何版本到任何其他版本都不向后兼容。

assert是三级公民的肩膀,它将在python4中完全删除,当然在Python 8.1中也将完全删除。

If you put the parenthesis in there because you wanted a multi-line assert, then an alternative is to put a backslash at the end of the line like this:

foo = 7
assert foo == 8, \
    "derp should be 8, it is " + str(foo)

Prints:

AssertionError: "derp should be 8, it is 7

Why does this python assert have to be different from everything else:

I think the pythonic ideology is that a program should self-correct without having to worry about the special flag to turn on asserts. The temptation to turn off asserts is too great, and thus it’s being deprecated.

I share your annoyance that the python assert has unique syntax relative to all other python programming constructs, and this syntax has yet again changed from python2 to python3 and again changed from python 3.4 to 3.6. Making assert statements not backward compatible from any version to any other version.

It’s a tap on the shoulder that assert is a 3rd class citizen, it will be totally removed in python4, and certainly again in Python 8.1.


回答 2

assert 1==2, "hi"被解析为assert 1==2, "hi"“ hi”作为关键字的第二个参数。因此,为什么它会正确地给出一个错误。

assert(1==2)之所以被解析为assert (1==2)与相同assert 1==2,是因为除非有尾随逗号,否则围绕单个项目的括号不会创建元组(1==2,)

assert(1==2, "hi")被解析为assert (1==2, "hi"),这不会产生错误,因为非空元组(False, "hi")不是假值,并且没有第二个参数提供给关键字。

您不应该使用括号,因为assert它不是Python中的函数-它是关键字。

assert 1==2, "hi" is parsed as assert 1==2, "hi" with “hi” as the second parameter for the keyword. Hence why it properly gives an error.

assert(1==2) is parsed as assert (1==2) which is identical to assert 1==2, because parens around a single item don’t create a tuple unless there’s a trailing comma e.g. (1==2,).

assert(1==2, "hi") is parsed as assert (1==2, "hi"), which doesn’t give an error because a non-empty tuple (False, "hi") isn’t a false value, and there is no second parameter supplied to the keyword.

You shouldn’t use parentheses because assert is not a function in Python – it’s a keyword.


回答 3

您可以不\这样来破坏assert语句:

foo = 7
assert foo == 8, (
    'derp should be 8, it is ' + str(foo))

或者,如果您有更长的消息:

foo = 7
assert foo == 8, (
    'Lorem Ipsum is simply dummy text of the printing and typesetting '
    'industry. Lorem Ipsum has been the industry\'s standard dummy text '
    'ever since the 1500s'
)

You can break assert statement without \ like this:

foo = 7
assert foo == 8, (
    'derp should be 8, it is ' + str(foo))

Or if you have even longer message:

foo = 7
assert foo == 8, (
    'Lorem Ipsum is simply dummy text of the printing and typesetting '
    'industry. Lorem Ipsum has been the industry\'s standard dummy text '
    'ever since the 1500s'
)

回答 4

以下是python doc中引用的内容

声明语句是将调试声明插入程序的便捷方法:

assert_stmt ::= "assert" expression ["," expression]

简单形式,断言表达式,等效于 if __debug__: if not expression: raise AssertionError

扩展形式,断言expression1,expression2等效于 if __debug__: if not expression1: raise AssertionError(expression2)

因此,当您在此处使用括号时,您使用的是简单形式,并且该表达式被评估为元组,当转换为布尔值时始终为True

Following is cited from the python doc

Assert statements are a convenient way to insert debugging assertions into a program:

assert_stmt ::= "assert" expression ["," expression]

The simple form, assert expression, is equivalent to if __debug__: if not expression: raise AssertionError

The extended form, assert expression1, expression2, is equivalent to if __debug__: if not expression1: raise AssertionError(expression2)

So when you’re using parenthesis here, you’re using the simple form, and the expression is evaluated as a tuple, which is always True when being casted to bool


如何(在运行时)检查一个类是否是另一个类的子类?

问题:如何(在运行时)检查一个类是否是另一个类的子类?

假设我有一个西服类和西服的四个子类:Heart,Spade,Diamond,Club。

class Suit:
   ...
class Heart(Suit):
   ...
class Spade(Suit):
   ...
class Diamond(Suit):
   ...
class Club(Suit):
   ...

我有一个方法,该方法接收西装作为参数,这是一个类对象,而不是实例。更准确地说,它可能仅接收以下四个值之一:Heart,Spade,Diamond,Club。我该如何做出保证这种事情的断言?就像是:

def my_method(suit):
   assert(suit subclass of Suit)
   ...

我正在使用Python 3。

Let’s say that I have a class Suit and four subclasses of suit: Heart, Spade, Diamond, Club.

class Suit:
   ...
class Heart(Suit):
   ...
class Spade(Suit):
   ...
class Diamond(Suit):
   ...
class Club(Suit):
   ...

I have a method which receives a suit as a parameter, which is a class object, not an instance. More precisely, it may receive only one of the four values: Heart, Spade, Diamond, Club. How can I make an assertion which ensures such a thing? Something like:

def my_method(suit):
   assert(suit subclass of Suit)
   ...

I’m using Python 3.


回答 0

您可以使用issubclass()像这样assert issubclass(suit, Suit)

You can use issubclass() like this assert issubclass(suit, Suit).


回答 1

issubclass(class, classinfo)

摘抄:

如果class是的子类(直接,间接或虚拟), 则返回true classinfo

issubclass(class, classinfo)

Excerpt:

Return true if class is a subclass (direct, indirect or virtual) of classinfo.


回答 2

isinstance如果您有实例或issubclass类,则可以使用。通常认为这是一个坏主意。通常,在Python中,您可以通过尝试对某个对象进行处理来确定该对象是否具有某种处理能力。

You can use isinstance if you have an instance, or issubclass if you have a class. Normally thought its a bad idea. Normally in Python you work out if an object is capable of something by attempting to do that thing to it.


回答 3

issubclass(sub, sup)如果给定的子类布尔函数返回真sub不愧是超类的子类sup

The issubclass(sub, sup) boolean function returns true if the given subclass sub is indeed a subclass of the superclass sup.


回答 4

issubclass 最小的可运行示例

这是带有一些断言的更完整的示例:

#!/usr/bin/env python3

class Base:
    pass

class Derived(Base):
    pass

base = Base()
derived = Derived()

# Basic usage.
assert issubclass(Derived, Base)
assert not issubclass(Base, Derived)

# True for same object.
assert issubclass(Base, Base)

# Cannot use object of class.
try:
    issubclass(derived, Base)
except TypeError:
    pass
else:
    assert False

# Do this instead.
assert isinstance(derived, Base)

GitHub上游

已在Python 3.5.2中测试。

issubclass minimal runnable example

Here is a more complete example with some assertions:

#!/usr/bin/env python3

class Base:
    pass

class Derived(Base):
    pass

base = Base()
derived = Derived()

# Basic usage.
assert issubclass(Derived, Base)
assert not issubclass(Base, Derived)

# True for same object.
assert issubclass(Base, Base)

# Cannot use object of class.
try:
    issubclass(derived, Base)
except TypeError:
    pass
else:
    assert False

# Do this instead.
assert isinstance(derived, Base)

GitHub upstream.

Tested in Python 3.5.2.


回答 5

您可以使用内置的issubclass。但是通常认为类型检查是不必要的,因为您可以使用鸭子类型。

You can use the builtin issubclass. But type checking is usually seen as unneccessary because you can use duck-typing.


回答 6

使用issubclass似乎是编写日志级别的一种干净方法。使用它有点奇怪…但是它看起来比其他选项更干净。

class Error(object): pass
class Warn(Error): pass
class Info(Warn): pass
class Debug(Info): pass

class Logger():
    LEVEL = Info

    @staticmethod
    def log(text,level):
        if issubclass(Logger.LEVEL,level):
            print(text)
    @staticmethod
    def debug(text):
        Logger.log(text,Debug)   
    @staticmethod
    def info(text):
        Logger.log(text,Info)
    @staticmethod
    def warn(text):
        Logger.log(text,Warn)
    @staticmethod
    def error(text):
        Logger.log(text,Error)

Using issubclass seemed like a clean way to write loglevels. It kinda feels odd using it… but it seems cleaner than other options.

class Error(object): pass
class Warn(Error): pass
class Info(Warn): pass
class Debug(Info): pass

class Logger():
    LEVEL = Info

    @staticmethod
    def log(text,level):
        if issubclass(Logger.LEVEL,level):
            print(text)
    @staticmethod
    def debug(text):
        Logger.log(text,Debug)   
    @staticmethod
    def info(text):
        Logger.log(text,Info)
    @staticmethod
    def warn(text):
        Logger.log(text,Warn)
    @staticmethod
    def error(text):
        Logger.log(text,Error)

回答 7

根据Python文档,我们还可以使用class.__mro__属性或class.mro()方法:

class Suit:
    pass
class Heart(Suit):
    pass
class Spade(Suit):
    pass
class Diamond(Suit):
    pass
class Club(Suit):
    pass

>>> Heart.mro()
[<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>]
>>> Heart.__mro__
(<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>)

Suit in Heart.mro()  # True
object in Heart.__mro__  # True
Spade in Heart.mro()  # False

According to the Python doc, we can also use class.__mro__ attribute or class.mro() method:

class Suit:
    pass
class Heart(Suit):
    pass
class Spade(Suit):
    pass
class Diamond(Suit):
    pass
class Club(Suit):
    pass

>>> Heart.mro()
[<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>]
>>> Heart.__mro__
(<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>)

Suit in Heart.mro()  # True
object in Heart.__mro__  # True
Spade in Heart.mro()  # False

回答 8

#issubclass(child,parent)

class a:
    pass
class b(a):
    pass
class c(b):
    pass

print(issubclass(c,b))#it returns true
#issubclass(child,parent)

class a:
    pass
class b(a):
    pass
class c(b):
    pass

print(issubclass(c,b))#it returns true

Python断言的最佳实践

问题:Python断言的最佳实践

  1. assert作为标准代码的一部分而不是仅用于调试目的,是否存在性能或代码维护问题?

    assert x >= 0, 'x is less than zero'

    胜过或坏于

    if x < 0:
        raise Exception, 'x is less than zero'
  2. 另外,是否有任何方法可以设置业务规则,例如if x < 0 raise error始终不进行检查,try/except/finally因此在整个代码中的任何时候都x小于0时,都会引发错误,例如assert x < 0在函数的开始处,函数内的任何位置进行设置哪里x变得小于0引发异常?

  1. Is there a performance or code maintenance issue with using assert as part of the standard code instead of using it just for debugging purposes?

    Is

    assert x >= 0, 'x is less than zero'
    

    better or worse than

    if x < 0:
        raise Exception, 'x is less than zero'
    
  2. Also, is there any way to set a business rule like if x < 0 raise error that is always checked without the try/except/finally so, if at anytime throughout the code x is less than 0 an error is raised, like if you set assert x < 0 at the start of a function, anywhere within the function where x becomes less then 0 an exception is raised?


回答 0

为了能够在整个函数中x小于零时自动引发错误。您可以使用类描述符。这是一个例子:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

To be able to automatically throw an error when x become less than zero throughout the function. You can use class descriptors. Here is an example:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

回答 1

应该使用断言来测试永远不会发生的条件。目的是在程序状态损坏的情况下尽早崩溃。

应该将异常用于可能发生的错误,并且几乎应该始终创建自己的Exception类


例如,如果您要编写一个从配置文件读取到的函数,则文件中dict不正确的格式将引发a ConfigurationSyntaxError,同时assert您可以避免返回None


在您的示例中,如果x是通过用户界面或外部来源设置的值,则最好是exceptions。

如果x仅由您自己的代码在同一程序中设置,请声明。

Asserts should be used to test conditions that should never happen. The purpose is to crash early in the case of a corrupt program state.

Exceptions should be used for errors that can conceivably happen, and you should almost always create your own Exception classes.


For example, if you’re writing a function to read from a configuration file into a dict, improper formatting in the file should raise a ConfigurationSyntaxError, while you can assert that you’re not about to return None.


In your example, if x is a value set via a user interface or from an external source, an exception is best.

If x is only set by your own code in the same program, go with an assertion.


回答 2

优化编译后,将删除“ assert”语句。因此,是的,在性能和功能上都存在差异。

当在编译时请求优化时,当前代码生成器不会为assert语句生成任何代码。- Python 2的文档 的Python 3文档

如果您用于assert实现应用程序功能,然后优化对生产的部署,那么“ but-it-works-in-dev”缺陷将给您带来困扰。

参见PYTHONOPTIMIZE-O -​​OO

“assert” statements are removed when the compilation is optimized. So, yes, there are both performance and functional differences.

The current code generator emits no code for an assert statement when optimization is requested at compile time. – Python 2 Docs Python 3 Docs

If you use assert to implement application functionality, then optimize the deployment to production, you will be plagued by “but-it-works-in-dev” defects.

See PYTHONOPTIMIZE and -O -OO


回答 3

的四个目的 assert

假设您与四个同事Alice,Bernd,Carl和Daphne一起处理了200,000行代码。他们叫您的代码,您叫他们的代码。

然后assert具有四个角色

  1. 告知Alice,Bernd,Carl和Daphne您的代码期望什么。
    假设您有一个处理元组列表的方法,并且如果这些元组不是不可变的,则程序逻辑可能会中断:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))

    比文档中的等效信息更值得信赖,并且更易于维护。

  2. 通知计算机您的代码期望什么。
    assert强制代码调用者采取适当的行为。如果您的代码调用了Alices的代码,而Bernd的代码调用了您的代码,则没有assert,如果程序在Alices代码中崩溃,Bernd可能认为这是Alice的错误,Alice进行了调查,并可能认为这是您的错误,您调查了并告诉Bernd实际上他的。很多工作丢失了。
    有了断言,无论谁打错电话,他们都将能够迅速看到这是他们的错,而不是您的错。爱丽丝,伯恩德,你们都将从中受益。节省大量时间。

  3. 通知您的代码(包括您自己)的读者在某些时候取得了什么成就。
    假设您有一个条目列表,并且每个条目都可以是干净的(很好),也可以是乱码,流浪汉,gullup或闪烁的(都不可接受)。如果它很轻便,必须将其清零。如果是流浪汉,则必须加以保护;如果它是古怪的,则必须将其放小(然后也可能要加快速度);如果已闪烁,则必须再次闪烁(星期四除外)。您会明白:这是复杂的东西。但是最终结果是(或应该是)所有条目都是干净的。Right Thing(TM)要做的是将清洁循环的效果总结为

    assert(all(entry.isClean() for entry in mylist))

    该报表节省了大家试图了解头痛究竟它是一个美妙的循环实现。这些人中最常出现的人可能就是你自己。

  4. 通知计算机您的代码在某些时候已经实现了什么。
    如果您在小跑后忘记了需要它的条目,assert它将节省您的时间,并避免您的代码在以后很长时间内破坏亲爱的达芙妮。

在我看来,assert文档的两个目的(1和3)和保障(2和4)同等重要。
通知人们甚至比通知计算机有价值,因为通知人们可以防止assert目标要抓住的错误(在情况1中)以及在任何情况下都可以避免许多后续错误。

The four purposes of assert

Assume you work on 200,000 lines of code with four colleagues Alice, Bernd, Carl, and Daphne. They call your code, you call their code.

Then assert has four roles:

  1. Inform Alice, Bernd, Carl, and Daphne what your code expects.
    Assume you have a method that processes a list of tuples and the program logic can break if those tuples are not immutable:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

    This is more trustworthy than equivalent information in the documentation and much easier to maintain.

  2. Inform the computer what your code expects.
    assert enforces proper behavior from the callers of your code. If your code calls Alices’s and Bernd’s code calls yours, then without the assert, if the program crashes in Alices code, Bernd might assume it was Alice’s fault, Alice investigates and might assume it was your fault, you investigate and tell Bernd it was in fact his. Lots of work lost.
    With asserts, whoever gets a call wrong, they will quickly be able to see it was their fault, not yours. Alice, Bernd, and you all benefit. Saves immense amounts of time.

  3. Inform the readers of your code (including yourself) what your code has achieved at some point.
    Assume you have a list of entries and each of them can be clean (which is good) or it can be smorsh, trale, gullup, or twinkled (which are all not acceptable). If it’s smorsh it must be unsmorshed; if it’s trale it must be baludoed; if it’s gullup it must be trotted (and then possibly paced, too); if it’s twinkled it must be twinkled again except on Thursdays. You get the idea: It’s complicated stuff. But the end result is (or ought to be) that all entries are clean. The Right Thing(TM) to do is to summarize the effect of your cleaning loop as

    assert(all(entry.isClean() for entry in mylist))
    

    This statements saves a headache for everybody trying to understand what exactly it is that the wonderful loop is achieving. And the most frequent of these people will likely be yourself.

  4. Inform the computer what your code has achieved at some point.
    Should you ever forget to pace an entry needing it after trotting, the assert will save your day and avoid that your code breaks dear Daphne’s much later.

In my mind, assert‘s two purposes of documentation (1 and 3) and safeguard (2 and 4) are equally valuable.
Informing the people may even be more valuable than informing the computer because it can prevent the very mistakes the assert aims to catch (in case 1) and plenty of subsequent mistakes in any case.


回答 4

除了其他答案外,断言本身会引发异常,但仅断言AssertionErrors。从功利主义的角度来看,断言不适用于需要精细控制所捕获的异常的情况。

In addition to the other answers, asserts themselves throw exceptions, but only AssertionErrors. From a utilitarian standpoint, assertions aren’t suitable for when you need fine grain control over which exceptions you catch.


回答 5

这种方法唯一真正出错的地方是,使用assert语句很难创建非常描述性的异常。如果您正在寻找更简单的语法,请记住您可以执行以下操作:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

另一个问题是,使用assert进行正常的条件检查是,使用-O标志很难禁用调试声明。

The only thing that’s really wrong with this approach is that it’s hard to make a very descriptive exception using assert statements. If you’re looking for the simpler syntax, remember you can also do something like this:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

Another problem is that using assert for normal condition-checking is that it makes it difficult to disable the debugging asserts using the -O flag.


回答 6

英语语言文字断言在这里的意义上使用发誓申明招认。这并不意味着“检查”“应该”。这意味着作为编码人员正在此处宣誓就职

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

如果代码正确,则除非发生单事件失败,硬件故障等,否则断言不会失败。这就是为什么不得影响最终用户的程序行为。特别是,断言即使在特殊的程序条件下也不会失败。只是从来没有发生过。如果发生这种情况,程序员应该对此进行调整。

The English language word assert here is used in the sense of swear, affirm, avow. It doesn’t mean “check” or “should be”. It means that you as a coder are making a sworn statement here:

# I solemnly swear that here I will tell the truth, the whole truth, 
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42

If the code is correct, barring Single-event upsets, hardware failures and such, no assert will ever fail. That is why the behaviour of the program to an end user must not be affected. Especially, an assert cannot fail even under exceptional programmatic conditions. It just doesn’t ever happen. If it happens, the programmer should be zapped for it.


回答 7

如前所述,当您的代码永远都不能达到目标时就应该使用断言,这意味着那里存在一个错误。我可以看到使用断言的最有用的原因可能是不变/前置/后置条件。这些在循环或函数的每次迭代的开始或结束时必须为真。

例如,一个递归函数(2个独立的函数,因此1个处理错误的输入,另一个处理错误的代码,导致很难通过递归来区分)。如果我忘记编写if语句,那将很明显地说明出了问题。

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

这些循环不变式通常可以用断言来表示。

As has been said previously, assertions should be used when your code SHOULD NOT ever reach a point, meaning there is a bug there. Probably the most useful reason I can see to use an assertion is an invariant/pre/postcondition. These are something that must be true at the start or end of each iteration of a loop or a function.

For example, a recursive function (2 seperate functions so 1 handles bad input and the other handles bad code, cause it’s hard to distinguish with recursion). This would make it obvious if I forgot to write the if statement, what had gone wrong.

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

These loop invariants often can be represented with an assertion.


回答 8

是否存在性能问题?

  • 请记住“先使其工作,然后再使其快速工作”
    通常,几乎没有任何程序的百分比与其速度有关。assert如果事实证明存在性能问题,您总是可以开除或简化它,而其中大多数绝不会。

  • 务实
    假设您有一种处理元组的非空列表的方法,并且如果这些元组不是不可变的,则程序逻辑将中断。您应该写:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))

    如果您的列表往往有十个条目,这可能很好,但是如果它们有一百万个条目,则可能会成为问题。但是,与其完全丢弃这张贵重的支票,不如将其降级为

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!

    这很便宜,但无论如何都会捕获大多数实际程序错误。

Is there a performance issue?

  • Please remember to “make it work first before you make it work fast”.
    Very few percent of any program are usually relevant for its speed. You can always kick out or simplify an assert if it ever proves to be a performance problem — and most of them never will.

  • Be pragmatic:
    Assume you have a method that processes a non-empty list of tuples and the program logic will break if those tuples are not immutable. You should write:

    def mymethod(listOfTuples):
        assert(all(type(tp)==tuple for tp in listOfTuples))
    

    This is probably fine if your lists tend to be ten entries long, but it can become a problem if they have a million entries. But rather than discarding this valuable check entirely you could simply downgrade it to

    def mymethod(listOfTuples):
        assert(type(listOfTuples[0])==tuple)  # in fact _all_ must be tuples!
    

    which is cheap but will likely catch most of the actual program errors anyway.


回答 9

好吧,这是一个悬而未决的问题,我想谈谈两个方面:何时添加断言以及如何编写错误消息。

目的

向初学者解释它-断言是可能引发错误的语句,但是您不会抓住它们。而且通常不应该将它们提高,但是在现实生活中,无论如何它们有时都会得到提高。这是一种严重的情况,代码无法从中恢复,我们称之为“致命错误”。

接下来,它是出于“调试目的”,虽然正确,但听起来很不屑一顾。我更喜欢“声明不变式,永远不应该被违反”的表述,尽管它在不同的初学者中的工作方式有所不同……有些“只懂它”,而另一些要么找不到用处,要么替换正常的异常,甚至用它控制流程。

样式

在Python中,assert它是语句,而不是函数!(请记住assert(False, 'is true')不会提高。但是,请注意:

何时以及如何编写可选的“错误消息”?

此acually适用于单元测试框架,其通常具有许多专用的方法来做断言(assertTrue(condition)assertFalse(condition), assertEqual(actual, expected)等)。它们通常还提供一种对断言进行评论的方法。

在一次性代码中,您可以不显示错误消息。

在某些情况下,没有要添加的断言:

def dump(something):断言isinstance(something,Dumpable)#…

但是除此之外,一条消息对于与其他程序员(有时是代码的交互用户,例如在Ipython / Jupyter等中)的交互用户很有用。

给他们提供信息,而不仅仅是泄漏内部实施细节。

代替:

assert meaningless_identifier <= MAGIC_NUMBER_XXX, 'meaningless_identifier is greater than MAGIC_NUMBER_XXX!!!'

写:

assert meaningless_identifier > MAGIC_NUMBER_XXX, 'reactor temperature above critical threshold'

甚至:

assert meaningless_identifier > MAGIC_NUMBER_XXX, f'reactor temperature({meaningless_identifier }) above critical threshold ({MAGIC_NUMBER_XXX})'

我知道,我知道-这不是静态断言的情况,但我想指出消息的信息价值。

消极或正面信息?

这可能是肯定的,但阅读以下内容会伤害我:

assert a == b, 'a is not equal to b'
  • 这是彼此矛盾的两件事。因此,只要我对代码库产生影响,我就会通过使用诸如“必须”和“应该”之类的多余动词来推动我们想要的内容,而不是说我们不需要的内容。

    断言a == b,’a必须等于b’

然后,获取AssertionError: a must be equal to b也是可读的,并且该语句在代码中看起来合乎逻辑。另外,您可以从中获得某些东西而无需阅读回溯(有时甚至不可用)。

Well, this is an open question, and I have two aspects that I want to touch on: when to add assertions and how to write the error messages.

Purpose

To explain it to a beginner – assertions are statements which can raise errors, but you won’t be catching them. And they normally should not be raised, but in real life they sometimes do get raised anyway. And this is a serious situation, which the code cannot recover from, what we call a ‘fatal error’.

Next, it’s for ‘debugging purposes’, which, while correct, sounds very dismissive. I like the ‘declaring invariants, which should never be violated’ formulation better, although it works differently on different beginners… Some ‘just get it’, and others either don’t find any use for it, or replace normal exceptions, or even control flow with it.

Style

In Python, assert is a statement, not a function! (remember assert(False, 'is true') will not raise. But, having that out of the way:

When, and how, to write the optional ‘error message’?

This acually applies to unit testing frameworks, which often have many dedicated methods to do assertions (assertTrue(condition), assertFalse(condition), assertEqual(actual, expected) etc.). They often also provide a way to comment on the assertion.

In throw-away code you could do without the error messages.

In some cases, there is nothing to add to the assertion:

def dump(something): assert isinstance(something, Dumpable) # …

But apart from that, a message is useful for communication with other programmers (which are sometimes interactive users of your code, e.g. in Ipython/Jupyter etc.).

Give them information, not just leak internal implementation details.

instead of:

assert meaningless_identifier <= MAGIC_NUMBER_XXX, 'meaningless_identifier is greater than MAGIC_NUMBER_XXX!!!'

write:

assert meaningless_identifier > MAGIC_NUMBER_XXX, 'reactor temperature above critical threshold'

or maybe even:

assert meaningless_identifier > MAGIC_NUMBER_XXX, f'reactor temperature({meaningless_identifier }) above critical threshold ({MAGIC_NUMBER_XXX})'

I know, I know – this is not a case for a static assertion, but I want to point to the informational value of the message.

Negative or positive message?

This may be conroversial, but it hurts me to read things like:

assert a == b, 'a is not equal to b'
  • these are two contradictory things written next to eachother. So whenever I have an influence on the codebase, I push for specifying what we want, by using extra verbs like ‘must’ and ‘should’, and not to say what we don’t want.

    assert a == b, ‘a must be equal to b’

Then, getting AssertionError: a must be equal to b is also readable, and the statement looks logical in code. Also, you can get something out of it without reading the traceback (which can sometimes not even be available).


回答 10

assert异常的使用和引发都与沟通有关。

  • 断言是关于开发人员要解决的代码正确性的声明:代码中的断言将代码的正确性告知读者,有关正确代码必须满足的条件。在运行时失败的断言通知开发人员代码中存在需要修复的缺陷。

  • 异常是关于非典型情况的指示,这些非典型情况可能在运行时发生,但不能被手头的代码解决,请在此处处理的调用代码处解决。发生异常并不表示代码中存在错误。

最佳实践

因此,如果您将运行时发生的特定情况视为要通知开发人员的错误(“开发人员,此情况表明某个地方存在错误,请修复代码。”)然后断言。如果断言检查代码的输入参数,则通常应在输入参数违反条件时向文档添加代码具有“未定义行为”的文档。

如果不是这样的情况的发生并不是您眼中的错误的迹象,而是您认为应该由客户端代码处理的(可能很少见但)可能的情况,请引发异常。引发异常的情况应该是相应代码文档的一部分。

使用时是否存在性能问题? assert

断言的评估需要一些时间。不过,可以在编译时将其消除。但是,这会带来一些后果,请参见下文。

使用时是否存在代码维护问题 assert

断言通常可以提高代码的可维护性,因为它们可以通过使假设明确化并在运行时定期验证这些假设来提高可读性。这也将有助于捕获回归。但是,需要牢记一个问题:断言中使用的表达式应该没有副作用。如上所述,可以在编译时消除断言-这意味着潜在的副作用也将消失。这可以-意外地-更改代码的行为。

Both the use of assert and the raising of exceptions are about communication.

  • Assertions are statements about the correctness of code addressed at developers: An assertion in the code informs readers of the code about conditions that have to be fulfilled for the code being correct. An assertion that fails at run-time informs developers that there is a defect in the code that needs fixing.

  • Exceptions are indications about non-typical situations that can occur at run-time but can not be resolved by the code at hand, addressed at the calling code to be handled there. The occurence of an exception does not indicate that there is a bug in the code.

Best practice

Therefore, if you consider the occurence of a specific situation at run-time as a bug that you would like to inform the developers about (“Hi developer, this condition indicates that there is a bug somewhere, please fix the code.”) then go for an assertion. If the assertion checks input arguments of your code, you should typically add to the documentation that your code has “undefined behaviour” when the input arguments violate that conditions.

If instead the occurrence of that very situation is not an indication of a bug in your eyes, but instead a (maybe rare but) possible situation that you think should rather be handled by the client code, raise an exception. The situations when which exception is raised should be part of the documentation of the respective code.

Is there a performance […] issue with using assert

The evaluation of assertions takes some time. They can be eliminated at compile time, though. This has some consequences, however, see below.

Is there a […] code maintenance issue with using assert

Normally assertions improve the maintainability of the code, since they improve readability by making assumptions explicit and during run-time regularly verifying these assumptions. This will also help catching regressions. There is one issue, however, that needs to be kept in mind: Expressions used in assertions should have no side-effects. As mentioned above, assertions can be eliminated at compile time – which means that also the potential side-effects would disappear. This can – unintendedly – change the behaviour of the code.


回答 11

声明将检查-1
.有效条件,
2.有效语句,
3.真实逻辑;
源代码。不会使整个项目失败,而是发出警报,指出源文件中不适当的内容。

在示例1中,由于变量’str’不为null。因此,不会引发任何断言或异常。

范例1:

#!/usr/bin/python

str = 'hello Python!'
strNull = 'string is Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
hello Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

在示例2中,var’str’为null。因此,我们可以通过assert语句来挽救用户,使其免于出现错误的程序。

范例2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
AssertionError: NULL String

当我们不想调试并意识到源代码中的断言问题时。禁用优化标志

python -O assertStatement.py
什么也不会得到打印

An Assert is to check –
1. the valid condition,
2. the valid statement,
3. true logic;
of source code. Instead of failing the whole project it gives an alarm that something is not appropriate in your source file.

In example 1, since variable ‘str’ is not null. So no any assert or exception get raised.

Example 1:

#!/usr/bin/python

str = 'hello Python!'
strNull = 'string is Null'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
hello Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py

In example 2, var ‘str’ is null. So we are saving the user from going ahead of faulty program by assert statement.

Example 2:

#!/usr/bin/python

str = ''
strNull = 'NULL String'

if __debug__:
    if not str: raise AssertionError(strNull)
print str

if __debug__:
    print 'FileName '.ljust(30,'.'),(__name__)
    print 'FilePath '.ljust(30,'.'),(__file__)


------------------------------------------------------

Output:
AssertionError: NULL String

The moment we don’t want debug and realized the assertion issue in the source code. Disable the optimization flag

python -O assertStatement.py
nothing will get print


回答 12

在PTVS,PyCharm等IDE中,assert isinstance()可以使用Wing 语句为一些不清楚的对象启用代码完成功能。

In IDE’s such as PTVS, PyCharm, Wing assert isinstance() statements can be used to enable code completion for some unclear objects.


回答 13

对于它的价值,如果您要处理依靠assert其正常运行的代码,那么添加以下代码将确保启用断言:

try:
    assert False
    raise Exception('Python assertions are not working. This tool relies on Python assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass

For what it’s worth, if you’re dealing with code which relies on assert to function properly, then adding the following code will ensure that asserts are enabled:

try:
    assert False
    raise Exception('Python assertions are not working. This tool relies on Python assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass

如何检查对象是列表还是元组(而不是字符串)?

问题:如何检查对象是列表还是元组(而不是字符串)?

这就是我通常做,以确定输入是一个list/ tuple-但不是str。因为很多时候我偶然发现了一个错误,即一个函数str错误地传递了一个对象,而目标函数确实for x in lst假定这lst实际上是一个listor tuple

assert isinstance(lst, (list, tuple))

我的问题是:是否有更好的方法来实现这一目标?

This is what I normally do in order to ascertain that the input is a list/tuple – but not a str. Because many times I stumbled upon bugs where a function passes a str object by mistake, and the target function does for x in lst assuming that lst is actually a list or tuple.

assert isinstance(lst, (list, tuple))

My question is: is there a better way of achieving this?


回答 0

仅在python 2中(不是python 3):

assert not isinstance(lst, basestring)

实际上就是您想要的,否则您会错过很多像列表一样的东西,但它们不是listor的子类tuple

In python 2 only (not python 3):

assert not isinstance(lst, basestring)

Is actually what you want, otherwise you’ll miss out on a lot of things which act like lists, but aren’t subclasses of list or tuple.


回答 1

请记住,在Python中,我们要使用“鸭子类型”。因此,任何类似列表的行为都可以视为列表。因此,不要检查列表的类型,只看它是否像列表一样。

但是字符串也像列表一样,通常这不是我们想要的。有时甚至是一个问题!因此,显式检查字符串,然后使用鸭子类型。

这是我写的一个有趣的函数。这是它的特殊版本,repr()可以在尖括号('<‘,’>’)中打印任何序列。

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

总体而言,这是干净优雅的。但是那张isinstance()支票在那里做什么?这是一种hack。但这是必不可少的。

该函数以递归方式调用类似于列表的任何对象。如果我们不专门处理字符串,则将其视为列表,并一次拆分一个字符。但是,然后递归调用将尝试将每个字符视为一个列表-它将起作用!即使是一个字符的字符串也可以作为列表!该函数将继续递归调用自身,直到堆栈溢出为止。

像这样的函数,依赖于每个递归调用来分解要完成的工作,必须使用特殊情况的字符串-因为您不能将字符串分解为一个字符以下的字符串,甚至不能分解为一个以下的字符串-字符字符串的作用类似于列表。

注意:try/ except是表达我们意图的最干净的方法。但是,如果这段代码在某种程度上对时间很紧迫,我们可能要用某种测试来替换它,看看是否arg是一个序列。除了测试类型,我们可能应该测试行为。如果它有一个.strip()方法,它是一个字符串,所以不要认为它是一个序列。否则,如果它是可索引的或可迭代的,则它是一个序列:

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))

def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

编辑:我最初写上面检查,__getslice__()但我注意到在collections模块文档中,有趣的方法是__getitem__(); 这很有意义,这就是您索引对象的方式。这似乎比根本,__getslice__()因此我更改了上面的内容。

Remember that in Python we want to use “duck typing”. So, anything that acts like a list can be treated as a list. So, don’t check for the type of a list, just see if it acts like a list.

But strings act like a list too, and often that is not what we want. There are times when it is even a problem! So, check explicitly for a string, but then use duck typing.

Here is a function I wrote for fun. It is a special version of repr() that prints any sequence in angle brackets (‘<‘, ‘>’).

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

This is clean and elegant, overall. But what’s that isinstance() check doing there? That’s kind of a hack. But it is essential.

This function calls itself recursively on anything that acts like a list. If we didn’t handle the string specially, then it would be treated like a list, and split up one character at a time. But then the recursive call would try to treat each character as a list — and it would work! Even a one-character string works as a list! The function would keep on calling itself recursively until stack overflow.

Functions like this one, that depend on each recursive call breaking down the work to be done, have to special-case strings–because you can’t break down a string below the level of a one-character string, and even a one-character string acts like a list.

Note: the try/except is the cleanest way to express our intentions. But if this code were somehow time-critical, we might want to replace it with some sort of test to see if arg is a sequence. Rather than testing the type, we should probably test behaviors. If it has a .strip() method, it’s a string, so don’t consider it a sequence; otherwise, if it is indexable or iterable, it’s a sequence:

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))

def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

EDIT: I originally wrote the above with a check for __getslice__() but I noticed that in the collections module documentation, the interesting method is __getitem__(); this makes sense, that’s how you index an object. That seems more fundamental than __getslice__() so I changed the above.


回答 2

H = "Hello"

if type(H) is list or type(H) is tuple:
    ## Do Something.
else
    ## Do Something.
H = "Hello"

if type(H) is list or type(H) is tuple:
    ## Do Something.
else
    ## Do Something.

回答 3

对于Python 3:

import collections.abc

if isinstance(obj, collections.abc.Sequence) and not isinstance(obj, str):
    print("obj is a sequence (list, tuple, etc) but not a string")

在版本3.3中进行了更改:将集合抽象基类移至collections.abc模块。为了向后兼容,它们在此模块中也将继续可见,直到3.8版将停止工作为止。

对于Python 2:

import collections

if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring):
    print "obj is a sequence (list, tuple, etc) but not a string or unicode"

For Python 3:

import collections.abc

if isinstance(obj, collections.abc.Sequence) and not isinstance(obj, str):
    print("obj is a sequence (list, tuple, etc) but not a string")

Changed in version 3.3: Moved Collections Abstract Base Classes to the collections.abc module. For backwards compatibility, they will continue to be visible in this module as well until version 3.8 where it will stop working.

For Python 2:

import collections

if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring):
    print "obj is a sequence (list, tuple, etc) but not a string or unicode"

回答 4

具有PHP风格的Python:

def is_array(var):
    return isinstance(var, (list, tuple))

Python with PHP flavor:

def is_array(var):
    return isinstance(var, (list, tuple))

回答 5

一般来说,在对象上进行迭代的函数不仅可以处理错误,还可以处理字符串,元组和列表。您当然可以使用isinstance或鸭式输入来检查参数,但是为什么要这么做呢?

这听起来像是个反问,但事实并非如此。答案为“为什么我应该检查参数的类型?” 可能会建议解决实际问题,而不是感知到的问题。将字符串传递给函数时,为什么会出错?另外:如果将字符串传递给此函数是一个错误,是否将其他非列表/元组可迭代传递给它也是一个错误吗?为什么或者为什么不?

我认为这个问题的最常见答案可能是 f("abc")期望该函数的行为就像编写的一样f(["abc"])。在某些情况下,保护开发人员免受自身侵害比支持对字符串中的字符进行迭代的用例更有意义。但是我首先会考虑很长时间。

Generally speaking, the fact that a function which iterates over an object works on strings as well as tuples and lists is more feature than bug. You certainly can use isinstance or duck typing to check an argument, but why should you?

That sounds like a rhetorical question, but it isn’t. The answer to “why should I check the argument’s type?” is probably going to suggest a solution to the real problem, not the perceived problem. Why is it a bug when a string is passed to the function? Also: if it’s a bug when a string is passed to this function, is it also a bug if some other non-list/tuple iterable is passed to it? Why, or why not?

I think that the most common answer to the question is likely to be that developers who write f("abc") are expecting the function to behave as though they’d written f(["abc"]). There are probably circumstances where it makes more sense to protect developers from themselves than it does to support the use case of iterating across the characters in a string. But I’d think long and hard about it first.


回答 6

尝试此操作以提高可读性和最佳做法:

Python2

import types
if isinstance(lst, types.ListType) or isinstance(lst, types.TupleType):
    # Do something

Python3

import typing
if isinstance(lst, typing.List) or isinstance(lst, typing.Tuple):
    # Do something

希望能帮助到你。

Try this for readability and best practices:

Python2

import types
if isinstance(lst, types.ListType) or isinstance(lst, types.TupleType):
    # Do something

Python3

import typing
if isinstance(lst, typing.List) or isinstance(lst, typing.Tuple):
    # Do something

Hope it helps.


回答 7

str对象没有__iter__属性

>>> hasattr('', '__iter__')
False 

所以你可以检查一下

assert hasattr(x, '__iter__')

这也AssertionError将为其他任何不可迭代的对象带来好处。

编辑: 正如蒂姆在评论中提到的那样,这仅适用于python 2.x,而不是3.x

The str object doesn’t have an __iter__ attribute

>>> hasattr('', '__iter__')
False 

so you can do a check

assert hasattr(x, '__iter__')

and this will also raise a nice AssertionError for any other non-iterable object too.

Edit: As Tim mentions in the comments, this will only work in python 2.x, not 3.x


回答 8

这并不是要直接回答OP,而是要分享一些相关想法。

我对上面的@steveha回答非常感兴趣,这似乎举了一个鸭子输入似乎中断的示例。换个角度说,他的例子表明鸭子的分类很难遵循,但是并不能说明str值得任何特殊处理。

毕竟,非str类型(例如,维护一些复杂的递归结构的用户定义类型)可能导致@steveha srepr函数引起无限递归。尽管这确实不太可能,但我们不能忽略这种可能性。因此,与其特殊外壳strsrepr,我们应该明确,我们想要什么srepr在无限递归产生时的事情情况。

似乎一种合理的方法是srepr暂时中断当前递归list(arg) == [arg]。这,其实,彻底解决这个问题str,没有任何isinstance

但是,真正复杂的递归结构可能会导致无限循环,list(arg) == [arg]永远不会发生。因此,尽管上面的检查很有用,但还不够。我们需要对递归深度进行严格限制。

我的观点是,如果您打算处理任意参数类型,则str通过鸭子类型进行处理要比处理(理论上)遇到的更通用类型容易得多。因此,如果您需要排除str实例,则应该要求该参数是您明确指定的几种类型之一的实例。

This is not intended to directly answer the OP, but I wanted to share some related ideas.

I was very interested in @steveha answer above, which seemed to give an example where duck typing seems to break. On second thought, however, his example suggests that duck typing is hard to conform to, but it does not suggest that str deserves any special handling.

After all, a non-str type (e.g., a user-defined type that maintains some complicated recursive structures) may cause @steveha srepr function to cause an infinite recursion. While this is admittedly rather unlikely, we can’t ignore this possibility. Therefore, rather than special-casing str in srepr, we should clarify what we want srepr to do when an infinite recursion results.

It may seem that one reasonable approach is to simply break the recursion in srepr the moment list(arg) == [arg]. This would, in fact, completely solve the problem with str, without any isinstance.

However, a really complicated recursive structure may cause an infinite loop where list(arg) == [arg] never happens. Therefore, while the above check is useful, it’s not sufficient. We need something like a hard limit on the recursion depth.

My point is that if you plan to handle arbitrary argument types, handling str via duck typing is far, far easier than handling the more general types you may (theoretically) encounter. So if you feel the need to exclude str instances, you should instead demand that the argument is an instance of one of the few types that you explicitly specify.


回答 9

在tensorflow中找到了一个名为is_sequence的函数

def is_sequence(seq):
  """Returns a true if its input is a collections.Sequence (except strings).
  Args:
    seq: an input sequence.
  Returns:
    True if the sequence is a not a string and is a collections.Sequence.
  """
  return (isinstance(seq, collections.Sequence)
and not isinstance(seq, six.string_types))

而且我已经证实它可以满足您的需求。

I find such a function named is_sequence in tensorflow.

def is_sequence(seq):
  """Returns a true if its input is a collections.Sequence (except strings).
  Args:
    seq: an input sequence.
  Returns:
    True if the sequence is a not a string and is a collections.Sequence.
  """
  return (isinstance(seq, collections.Sequence)
and not isinstance(seq, six.string_types))

And I have verified that it meets your needs.


回答 10

我在测试用例中执行此操作。

def assertIsIterable(self, item):
    #add types here you don't want to mistake as iterables
    if isinstance(item, basestring): 
        raise AssertionError("type %s is not iterable" % type(item))

    #Fake an iteration.
    try:
        for x in item:
            break;
    except TypeError:
        raise AssertionError("type %s is not iterable" % type(item))

未经生成器测试,我认为如果通过生成器,您将处于下一个“收益”状态,这可能会使下游情况恶化。但是再说一次,这是一个“单元测试”

I do this in my testcases.

def assertIsIterable(self, item):
    #add types here you don't want to mistake as iterables
    if isinstance(item, basestring): 
        raise AssertionError("type %s is not iterable" % type(item))

    #Fake an iteration.
    try:
        for x in item:
            break;
    except TypeError:
        raise AssertionError("type %s is not iterable" % type(item))

Untested on generators, I think you are left at the next ‘yield’ if passed in a generator, which may screw things up downstream. But then again, this is a ‘unittest’


回答 11

以“鸭子打字”的方式

try:
    lst = lst + []
except TypeError:
    #it's not a list

要么

try:
    lst = lst + ()
except TypeError:
    #it's not a tuple

分别。这避免了isinstance/ hasattr内省的东西。

您也可以反之亦然:

try:
    lst = lst + ''
except TypeError:
    #it's not (base)string

所有变体实际上都不会更改变量的内容,而是暗示了重新分配。我不确定这在某些情况下是否不受欢迎。

有趣的是,在任何情况下,如果是列表(不是元组),则在“就地”赋值时都不会引发+=no 。这就是为什么以这种方式完成分配的原因。也许有人可以阐明原因。TypeErrorlst

In “duck typing” manner, how about

try:
    lst = lst + []
except TypeError:
    #it's not a list

or

try:
    lst = lst + ()
except TypeError:
    #it's not a tuple

respectively. This avoids the isinstance / hasattr introspection stuff.

You could also check vice versa:

try:
    lst = lst + ''
except TypeError:
    #it's not (base)string

All variants do not actually change the content of the variable, but imply a reassignment. I’m unsure whether this might be undesirable under some circumstances.

Interestingly, with the “in place” assignment += no TypeError would be raised in any case if lst is a list (not a tuple). That’s why the assignment is done this way. Maybe someone can shed light on why that is.


回答 12

最简单的方法…使用anyisinstance

>>> console_routers = 'x'
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
False
>>>
>>> console_routers = ('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
>>> console_routers = list('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True

simplest way… using any and isinstance

>>> console_routers = 'x'
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
False
>>>
>>> console_routers = ('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True
>>> console_routers = list('x',)
>>> any([isinstance(console_routers, list), isinstance(console_routers, tuple)])
True

回答 13

鸭式打字的另一种形式,可以帮助区分类似字符串的对象和其他类似序列的对象。

类字符串对象的字符串表示形式是字符串本身,因此您可以检查是否从str构造函数中返回了相等的对象:

# If a string was passed, convert it to a single-element sequence
if var == str(var):
    my_list = [var]

# All other iterables
else: 
    my_list = list(var)

这应该适用于与str所有可迭代对象兼容的所有对象。

Another version of duck-typing to help distinguish string-like objects from other sequence-like objects.

The string representation of string-like objects is the string itself, so you can check if you get an equal object back from the str constructor:

# If a string was passed, convert it to a single-element sequence
if var == str(var):
    my_list = [var]

# All other iterables
else: 
    my_list = list(var)

This should work for all objects compatible with str and for all kinds of iterable objects.


回答 14

Python 3具有以下功能:

from typing import List

def isit(value):
    return isinstance(value, List)

isit([1, 2, 3])  # True
isit("test")  # False
isit({"Hello": "Mars"})  # False
isit((1, 2))  # False

因此,要同时检查列表和元组,将是:

from typing import List, Tuple

def isit(value):
    return isinstance(value, List) or isinstance(value, Tuple)

Python 3 has this:

from typing import List

def isit(value):
    return isinstance(value, List)

isit([1, 2, 3])  # True
isit("test")  # False
isit({"Hello": "Mars"})  # False
isit((1, 2))  # False

So to check for both Lists and Tuples, it would be:

from typing import List, Tuple

def isit(value):
    return isinstance(value, List) or isinstance(value, Tuple)

回答 15

assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"
assert (type(lst) == list) | (type(lst) == tuple), "Not a valid lst type, cannot be string"

回答 16

做这个

if type(lst) in (list, tuple):
    # Do stuff

Just do this

if type(lst) in (list, tuple):
    # Do stuff

回答 17

在python> 3.6中

import collections
isinstance(set(),collections.abc.Container)
True
isinstance([],collections.abc.Container)
True
isinstance({},collections.abc.Container)
True
isinstance((),collections.abc.Container)
True
isinstance(str,collections.abc.Container)
False

in python >3.6

import collections
isinstance(set(),collections.abc.Container)
True
isinstance([],collections.abc.Container)
True
isinstance({},collections.abc.Container)
True
isinstance((),collections.abc.Container)
True
isinstance(str,collections.abc.Container)
False

回答 18

我倾向于这样做(如果真的必须这样做的话):

for i in some_var:
   if type(i) == type(list()):
       #do something with a list
   elif type(i) == type(tuple()):
       #do something with a tuple
   elif type(i) == type(str()):
       #here's your string

I tend to do this (if I really, really had to):

for i in some_var:
   if type(i) == type(list()):
       #do something with a list
   elif type(i) == type(tuple()):
       #do something with a tuple
   elif type(i) == type(str()):
       #here's your string

Python中“ assert”的用法是什么?

问题:Python中“ assert”的用法是什么?

我一直在阅读一些源代码,并且在几个地方看到了的用法assert

到底是什么意思?它的用途是什么?

I have been reading some source code and in several places I have seen the usage of assert.

What does it mean exactly? What is its usage?


回答 0

assert语句几乎存在于每种编程语言中。它有助于在程序中尽早发现问题,找出原因,而不是在其他操作后再发现问题。

当你做…

assert condition

…您要告诉程序测试该条件,如果条件为假,则立即触发错误。

在Python中,它大致等于:

if not condition:
    raise AssertionError()

在Python Shell中尝试:

>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

断言可以包括可选消息,您可以在运行解释器时将其禁用。

要在断言失败时打印消息:

assert False, "Oh no! This assertion failed!"

千万不能使用括号调用assert的功能等。这是一个声明。如果你这样做assert(condition, message)你会运行assert一个(condition, message)元组的第一个参数。

至于禁用它们,运行时,python在优化模式,其中__debug__False,断言语句将被忽略。只要通过-O标志:

python -O script.py

有关相关文档,请参见此处

The assert statement exists in almost every programming language. It helps detect problems early in your program, where the cause is clear, rather than later as a side-effect of some other operation.

When you do…

assert condition

… you’re telling the program to test that condition, and immediately trigger an error if the condition is false.

In Python, it’s roughly equivalent to this:

if not condition:
    raise AssertionError()

Try it in the Python shell:

>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Assertions can include an optional message, and you can disable them when running the interpreter.

To print a message if the assertion fails:

assert False, "Oh no! This assertion failed!"

Do not use parenthesis to call assert like a function. It is a statement. If you do assert(condition, message) you’ll be running the assert with a (condition, message) tuple as first parameter.

As for disabling them, when running python in optimized mode, where __debug__ is False, assert statements will be ignored. Just pass the -O flag:

python -O script.py

See here for the relevant documentation.


回答 1

注意括号。正如上面指出的那样,在Python 3中,assert它仍然是一条语句,因此与类似print(..),可以将其外推到assert(..)raise(..)但不应该外推。

这很重要,因为:

assert(2 + 2 == 5, "Houston we've got a problem")

不起作用,不像

assert 2 + 2 == 5, "Houston we've got a problem"

第一个不起作用的原因是bool( (False, "Houston we've got a problem") )评估为True

在语句中assert(False),这些只是多余的括号False,对它们的内容进行求值。但是assert(False,)现在带括号的是一个元组,非空元组的计算结果为True布尔值。

Watch out for the parentheses. As has been pointed out above, in Python 3, assert is still a statement, so by analogy with print(..), one may extrapolate the same to assert(..) or raise(..) but you shouldn’t.

This is important because:

assert(2 + 2 == 5, "Houston we've got a problem")

won’t work, unlike

assert 2 + 2 == 5, "Houston we've got a problem"

The reason the first one will not work is that bool( (False, "Houston we've got a problem") ) evaluates to True.

In the statement assert(False), these are just redundant parentheses around False, which evaluate to their contents. But with assert(False,) the parentheses are now a tuple, and a non-empty tuple evaluates to True in a boolean context.


回答 2

正如其他答案所指出的,assert类似于在给定条件不成立时引发异常。一个重要的区别是,如果使用优化选项编译代码,则assert语句将被忽略-O。该文档说,assert expression可以更好地描述为等同于

if __debug__:
   if not expression: raise AssertionError

如果您要彻底测试代码,然后在满意所有断言都不失败的情况下发布优化版本,这将非常有用-当优化打开时,__debug__变量变为False且条件将不再被求值。如果您依靠断言并且没有意识到它们已经消失,那么此功能还可以吸引您。

As other answers have noted, assert is similar to throwing an exception if a given condition isn’t true. An important difference is that assert statements get ignored if you compile your code with the optimization option -O. The documentation says that assert expression can better be described as being equivalent to

if __debug__:
   if not expression: raise AssertionError

This can be useful if you want to thoroughly test your code, then release an optimized version when you’re happy that none of your assertion cases fail – when optimization is on, the __debug__ variable becomes False and the conditions will stop getting evaluated. This feature can also catch you out if you’re relying on the asserts and don’t realize they’ve disappeared.


回答 3

Python中断言的目的是通知开发人员程序中不可恢复的错误。

断言并不旨在表示预期的错误情况,例如“找不到文件”,用户可以在其中采取纠正措施(或只是再试一次)。

另一种看待它的方式是说断言是代码中的内部自检。它们通过在代码中声明某些条件是不可能的来工作的。如果不满足这些条件,则意味着程序中存在错误。

如果您的程序没有错误,则这些情况将永远不会发生。但是,如果确实发生了其中一种情况,则程序将因声明错误而崩溃,并确切地告诉您触发了哪个“不可能”条件。这使查找和修复程序中的错误变得更加容易。

这是我写的有关Python断言的教程的摘要:

Python的assert语句是一种调试辅助工具,而不是用于处理运行时错误的机制。使用断言的目的是让开发人员更快地找到错误的可能根本原因。除非程序中存在错误,否则永远不会引发断言错误。

The goal of an assertion in Python is to inform developers about unrecoverable errors in a program.

Assertions are not intended to signal expected error conditions, like “file not found”, where a user can take corrective action (or just try again).

Another way to look at it is to say that assertions are internal self-checks in your code. They work by declaring some conditions as impossible in your code. If these conditions don’t hold that means there’s a bug in the program.

If your program is bug-free, these conditions will never occur. But if one of them does occur the program will crash with an assertion error telling you exactly which “impossible” condition was triggered. This makes it much easier to track down and fix bugs in your programs.

Here’s a summary from a tutorial on Python’s assertions I wrote:

Python’s assert statement is a debugging aid, not a mechanism for handling run-time errors. The goal of using assertions is to let developers find the likely root cause of a bug more quickly. An assertion error should never be raised unless there’s a bug in your program.


回答 4

其他人已经为您提供了指向文档的链接。

您可以在交互式外壳中尝试以下操作:

>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
builtins.AssertionError:

第一条语句什么也不做,而第二条语句引发异常。这是第一个提示:断言对于检查在代码的给定位置应为真的条件(通常是函数的开始(前提)和结束(条件))很有用。

断言实际上与合同编程高度相关,这是非常有用的工程实践:

http://en.wikipedia.org/wiki/Design_by_contract

Others have already given you links to documentation.

You can try the following in a interactive shell:

>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
builtins.AssertionError:

The first statement does nothing, while the second raises an exception. This is the first hint: asserts are useful to check conditions that should be true in a given position of your code (usually, the beginning (preconditions) and the end of a function (postconditions)).

Asserts are actually highly tied to programming by contract, which is a very useful engineering practice:

http://en.wikipedia.org/wiki/Design_by_contract.


回答 5

从文档:

Assert statements are a convenient way to insert debugging assertions into a program

在这里您可以阅读更多信息:http : //docs.python.org/release/2.5.2/ref/assert.html

From docs:

Assert statements are a convenient way to insert debugging assertions into a program

Here you can read more: http://docs.python.org/release/2.5.2/ref/assert.html


回答 6

assert语句有两种形式。

简单形式assert <expression>相当于

if __debug__:
    if not <expression>: raise AssertionError

扩展形式assert <expression1>, <expression2>相当于

if __debug__:
    if not <expression1>: raise AssertionError, <expression2>

The assert statement has two forms.

The simple form, assert <expression>, is equivalent to

if __​debug__:
    if not <expression>: raise AssertionError

The extended form, assert <expression1>, <expression2>, is equivalent to

if __​debug__:
    if not <expression1>: raise AssertionError, <expression2>

回答 7

断言是检查程序内部状态是否符合程序员预期的一种系统方法,目的是捕获错误。请参见下面的示例。

>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>> 

Assertions are a systematic way to check that the internal state of a program is as the programmer expected, with the goal of catching bugs. See the example below.

>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>> 

回答 8

这是一个简单的示例,将其保存在文件中(假设为b.py)

def chkassert(num):
    assert type(num) == int


chkassert('a')

结果是什么时候 $python b.py

Traceback (most recent call last):
  File "b.py", line 5, in <module>
    chkassert('a')
  File "b.py", line 2, in chkassert
    assert type(num) == int
AssertionError

Here is a simple example, save this in file (let’s say b.py)

def chkassert(num):
    assert type(num) == int


chkassert('a')

and the result when $python b.py

Traceback (most recent call last):
  File "b.py", line 5, in <module>
    chkassert('a')
  File "b.py", line 2, in chkassert
    assert type(num) == int
AssertionError

回答 9

如果assert后的语句为true,则程序继续;但是,如果assert后的语句为false,则程序给出错误。就那么简单。

例如:

assert 1>0   #normal execution
assert 0>1   #Traceback (most recent call last):
             #File "<pyshell#11>", line 1, in <module>
             #assert 0>1
             #AssertionError

if the statement after assert is true then the program continues , but if the statement after assert is false then the program gives an error. Simple as that.

e.g.:

assert 1>0   #normal execution
assert 0>1   #Traceback (most recent call last):
             #File "<pyshell#11>", line 1, in <module>
             #assert 0>1
             #AssertionError

回答 10

assert语句几乎存在于每种编程语言中。它有助于在程序中尽早发现问题,找出原因,而不是在其他操作后再发现问题。他们总是期待一个True条件。

当您执行以下操作时:

assert condition

您要告诉程序测试该条件并在错误的情况下立即触发错误。

在Python中,assertexpression等效于:

if __debug__:
    if not <expression>: raise AssertionError

您可以使用扩展表达式来传递可选消息

if __debug__:
    if not (expression_1): raise AssertionError(expression_2)

在Python解释器中尝试一下:

>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

在主要针对那些认为在assertif语句之间切换的人使用它们之前,有一些注意事项。使用的目的assert是在程序验证条件并返回应立即停止程序的值的情况下,而不是采取某些替代方法来绕过错误:

1.括号

您可能已经注意到,该assert语句使用两个条件。因此,千万不能使用括号englobe他们作为一个显而易见的建议。如果您这样做:

assert (condition, message)

例:

>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

您将以代表元组的第一个参数运行assert带有的a (condition, message),这是因为Python中的非空元组始终为True。但是,您可以单独进行而不会出现问题:

assert (condition), "message"

例:

>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.

2.调试目的

如果您想知道何时使用assert语句。举一个在现实生活中使用的例子:

*当您的程序倾向于控制用户输入的每个参数或其他任何参数时:

def loremipsum(**kwargs):
    kwargs.pop('bar') # return 0 if "bar" isn't in parameter
    kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
    assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())

*数学上的另一种情况是某个方程式的系数或常数为0或非正数:

def discount(item, percent):
    price = int(item['price'] * (1.0 - percent))
    print(price)
    assert (0 <= price <= item['price']),\
            "Discounted prices cannot be lower than 0 "\
            "and they cannot be higher than the original price."

    return price

*甚至是布尔实现的简单示例:

def true(a, b):
    assert (a == b), "False"
    return 1

def false(a, b):
    assert (a != b), "True"
    return 0

3.数据处理或数据验证

最重要的是不要依赖该assert语句执行数据处理或数据验证,因为可以在Python初始化时使用-O-OO标志(分别表示值1、2和0(默认值)或PYTHONOPTIMIZE环境变量)关闭此语句。。

值1:

*断言被禁用;

*使用.pyo扩展名而不是.pyc; 生成字节码文件;

* sys.flags.optimize设置为1(True);

*和,__debug__设置为False;

值2:再禁用一件事

*文档字符串被禁用;

因此,使用该assert语句来验证某种预期数据非常危险,这甚至暗示了某些安全问题。然后,如果您需要验证某些权限,我建议您raise AuthError代替。作为先决条件,assert程序员通常在没有用户直接交互的库或模块上使用an 。

The assert statement exists in almost every programming language. It helps detect problems early in your program, where the cause is clear, rather than later as a side-effect of some other operation. They always expect a True condition.

When you do something like:

assert condition

You’re telling the program to test that condition and immediately trigger an error if it is false.

In Python, assert expression, is equivalent to:

if __debug__:
    if not <expression>: raise AssertionError

You can use the extended expression to pass an optional message:

if __debug__:
    if not (expression_1): raise AssertionError(expression_2)

Try it in the Python interpreter:

>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

There are some caveats to seen before using them mainly for those who deem to toggles between the assert and if statements. The aim to use assert is on occasions when the program verifies a condition and return a value that should stop the program immediately instead of taking some alternative way to bypass the error:

1. Parentheses

As you may have noticed, the assert statement uses two conditions. Hence, do not use parentheses to englobe them as one for obvious advice. If you do such as:

assert (condition, message)

Example:

>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

You will be running the assert with a (condition, message) which represents a tuple as the first parameter, and this happens cause non-empty tuple in Python is always True. However, you can do separately without problem:

assert (condition), "message"

Example:

>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.

2. Debug purpose

If you are wondering regarding when use assert statement. Take an example used in real life:

* When your program tends to control each parameter entered by the user or whatever else:

def loremipsum(**kwargs):
    kwargs.pop('bar') # return 0 if "bar" isn't in parameter
    kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
    assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())

* Another case is on math when 0 or non-positive as a coefficient or constant on a certain equation:

def discount(item, percent):
    price = int(item['price'] * (1.0 - percent))
    print(price)
    assert (0 <= price <= item['price']),\
            "Discounted prices cannot be lower than 0 "\
            "and they cannot be higher than the original price."

    return price

* or even a simple example of a boolean implementation:

def true(a, b):
    assert (a == b), "False"
    return 1

def false(a, b):
    assert (a != b), "True"
    return 0

3. Data processing or data validation

The utmost importance is to not rely on the assert statement to execute data processing or data validation because this statement can be turned off on the Python initialization with -O or -OO flag – meaning value 1, 2, and 0 (as default), respectively – or PYTHONOPTIMIZE environment variable.

Value 1:

* asserts are disabled;

* bytecode files are generated using .pyo extension instead of .pyc;

* sys.flags.optimize is set to 1 (True);

* and, __debug__ is set to False;

Value 2: disables one more stuff

* docstrings are disabled;

Therefore, using the assert statement to validate a sort of expected data is extremely dangerous, implying even to some security issues. Then, if you need to validate some permission I recommend you raise AuthError instead. As a preconditional effective, an assert is commonly used by programmers on libraries or modules that do not have a user interact directly.


回答 11

正如在C2 Wiki上简要概述的那样:

断言是程序中特定点的布尔表达式,除非程序中存在错误,否则该表达式为真

您可以使用一条assert语句来记录您在特定程序点上对代码的理解。例如,您可以记录关于输入(前提条件),程序状态(不变式)或输出(后置条件)的假设或保证。

如果您的断言失败了,这将向您(或您的后继者)发出警报,提醒您在编写程序时对程序的理解是错误的,并且可能包含错误。

有关更多信息,John Regehr在“ Assertions”中有一篇精彩的博客文章,该文章也适用于Python assert语句。

As summarized concisely on the C2 Wiki:

An assertion is a boolean expression at a specific point in a program which will be true unless there is a bug in the program.

You can use an assert statement to document your understanding of the code at a particular program point. For example, you can document assumptions or guarantees about inputs (preconditions), program state (invariants), or outputs (postconditions).

Should your assertion ever fail, this is an alert for you (or your successor) that your understanding of the program was wrong when you wrote it, and that it likely contains a bug.

For more information, John Regehr has a wonderful blog post on the Use of Assertions, which applies to the Python assert statement as well.


回答 12

如果您想确切知道保留函数在python中的作用,请输入 help(enter_keyword)

确保您输入的保留关键字是否作为字符串输入。

If you ever want to know exactly what a reserved function does in python, type in help(enter_keyword)

Make sure if you are entering a reserved keyword that you enter it as a string.


回答 13

Python 断言基本上是一种调试辅助工具,用于测试代码内部自检的条件。当代码陷入不可能的情况时,Assert使调试变得非常容易。断言检查那些不可能的情况。

假设有一个函数可以计算折扣后的商品价格:

def calculate_discount(price, discount):
    discounted_price = price - [discount*price]
    assert 0 <= discounted_price <= price
    return discounted_price

在这里,Discounted_price永远不能小于0且大于实际价格。因此,如果违反了上述条件,则assert会引发Assertion Error,这将有助于开发人员识别出某些不可能的事情发生了。

希望能帮助到你 :)

Python assert is basically a debugging aid which test condition for internal self-check of your code. Assert makes debugging really easy when your code gets into impossible edge cases. Assert check those impossible cases.

Let’s say there is a function to calculate price of item after discount :

def calculate_discount(price, discount):
    discounted_price = price - [discount*price]
    assert 0 <= discounted_price <= price
    return discounted_price

here, discounted_price can never be less than 0 and greater than actual price. So, in case the above condition is violated assert raises an Assertion Error, which helps the developer to identify that something impossible had happened.

Hope it helps :)


回答 14

我的简短解释是:

  • assertAssertionError如果expression为false,则引发,否则继续执行代码,如果有逗号,则为AssertionError: whatever after comma,并且代码如下:raise AssertionError(whatever after comma)

有关此的相关教程:

https://www.tutorialspoint.com/python/assertions_in_python.htm

My short explanation is:

  • assert raises AssertionError if expression is false, otherwise just continues the code, and if there’s a comma whatever it is it will be AssertionError: whatever after comma, and to code is like: raise AssertionError(whatever after comma)

A related tutorial about this:

https://www.tutorialspoint.com/python/assertions_in_python.htm


回答 15

在Pycharm中,如果assert与一起使用isinstance来声明对象的类型,它将使您在编码时可以访问父对象的方法和属性,它将自动自动完成。

例如,假设self.object1.object2是一个MyClass对象。

import MyClasss

def code_it(self):
    testObject = self.object1.object2 # at this point, program doesn't know that testObject  is a MyClass object yet
    assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
    testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject

In Pycharm, if you use assert along with isinstance to declare an object’s type, it will let you access the methods and attributes of the parent object while you are coding, it will auto-complete automatically.

For example, let’s say self.object1.object2 is a MyClass object.

import MyClasss

def code_it(self):
    testObject = self.object1.object2 # at this point, program doesn't know that testObject  is a MyClass object yet
    assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
    testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject

回答 16

如在其他答案中所写,assert语句用于检查给定点的程序状态。

我不会重复有关关联消息,括号或-O选项和__debug__常量的内容。另请查阅文档以获取第一手信息。我将重点关注您的问题:的用途是assert什么?更准确地说,何时(何时不该使用)assert

assert语句对于调试程序很有用,但不鼓励检查用户输入。我使用以下经验法则:保留断言以检测这种不应该发生的情况。用户输入可能不正确,例如密码太短,但这不是不应该发生的情况。如果圆的直径不是其半径的两倍,则在这种情况不应该发生

最有趣的,在我脑海里,使用的assert是由灵感 合同编程为[面向对象的软件建设]由B.迈耶描述( https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction% 2C_2nd_Edition )并以[Eiffel编程语言](https://en.wikipedia.org/wiki/Eiffel_ (programming_language )实施。您不能使用该assert语句通过合同完全模拟编程,但是保持意图很有趣。

这是一个例子。想象一下,您必须编写一个head函数(例如headHaskell中的[ 函数]( http://www.zvon.org/other/haskell/Outputprelude/head_f.html))。给出的规范是:“如果列表不为空,则返回列表的第一项”。查看以下实现:

>>> def head1(xs): return xs[0]

>>> def head2(xs):
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

(是的,可以写成return xs[0] if xs else None,但这不是重点)

如果列表不为空,则两个函数的结果相同,并且此结果正确:

>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True

因此,这两种实现都是(我希望)正确的。当您尝试采用空列表的标题时,它们会有所不同:

>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range

但:

>>> head2([]) is None
True

同样,这两种实现都是正确的,因为没有人应该将空列表传递给这些函数(我们超出了规范)。那是一个不正确的电话,但是如果您进行这样的电话,任何事情都会发生。一个函数引发异常,另一个函数返回一个特殊值。最重要的是:我们不能依靠这种行为。如果xs为空,则可以使用:

print(head2(xs))

但这将使程序崩溃:

print(head1(xs))

为避免意外,我想知道何时将一些意外的参数传递给函数。换句话说:我想知道何时可观察的行为不可靠,因为它取决于实现而不是规范。当然,我可以阅读规范,但是程序员并不总是仔细阅读文档。

想象一下,如果我有一种方法可以将规范插入代码中以达到以下效果:当我违反规范时,例如,通过向传递一个空列表head,我会得到警告。这将对编写正确的(即符合规范的)程序有很大的帮助。这就是assert 进入现场的地方:

>>> def head1(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     return xs[0]

>>> def head2(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

现在,我们有:

>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

和:

>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

请注意,它head1抛出一个AssertionError,而不是IndexError。这很重要,因为an AssertionError并不是任何运行时错误:它表示违反规范。我想要警告,但出现错误。幸运的是,我可以禁用该检查(使用该-O选项),但后果自负。我会做到的,崩溃真的很昂贵,并且希望最好。想象一下,我的程序嵌入在穿过黑洞的宇宙飞船中。我将禁用断言,并希望该程序足够健壮,以免崩溃的时间尽可能长。

此示例仅与前提条件有关,因为您可以使用它assert来检查后置条件(返回值和/或状态)和不变式(类的状态)。请注意,检查后置条件和不变量with assert可能很麻烦:

  • 对于后置条件,需要将返回值分配给变量,并且如果要处理方法,则可能需要存储对象的初始状态;
  • 对于不变式,您必须在方法调用之前和之后检查状态。

您不会拥有像Eiffel那样复杂的功能,但是可以提高程序的整体质量。


总而言之,该assert语句是检测这种不应该发生的情况的便捷方法。违反规范(例如,向传递一个空列表head)是头等舱,这种情况不应该发生。因此,尽管该assert语句可用于检测任何意外情况,但这是确保满足规范的一种特权方式。一旦将assert语句插入代码中以表示规范,我们就可以希望您提高了程序的质量,因为将报告错误的参数,错误的返回值,错误的类状态…。

As written in other answers, assert statements are used to check the state of the program at a given point.

I won’t repeat what was said about associated message, parentheses, or -O option and __debug__ constant. Check also the doc for first hand information. I will focus on your question: what is the use of assert? More precisely, when (and when not) should one use assert?

The assert statements are useful to debug a program, but discouraged to check user input. I use the following rule of thumb: keep assertions to detect a this should not happen situation. A user input may be incorrect, e.g. a password too short, but this is not a this should not happen case. If the diameter of a circle is not twice as large as its radius, you are in a this should not happen case.

The most interesting, in my mind, use of assert is inspired by the programming by contract as described by B. Meyer in [Object-Oriented Software Construction]( https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction%2C_2nd_Edition ) and implemented in the [Eiffel programming language]( https://en.wikipedia.org/wiki/Eiffel_(programming_language)). You can’t fully emulate programming by contract using the assert statement, but it’s interesting to keep the intent.

Here’s an example. Imagine you have to write a head function (like the [head function in Haskell]( http://www.zvon.org/other/haskell/Outputprelude/head_f.html)). The specification you are given is: “if the list is not empty, return the first item of a list”. Look at the following implementations:

>>> def head1(xs): return xs[0]

And

>>> def head2(xs):
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

(Yes, this can be written as return xs[0] if xs else None, but that’s not the point).

If the list is not empty, both functions have the same result and this result is correct:

>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True

Hence, both implementations are (I hope) correct. They differ when you try to take the head item of an empty list:

>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range

But:

>>> head2([]) is None
True

Again, both implementations are correct, because no one should pass an empty list to these functions (we are out of the specification). That’s an incorrect call, but if you do such a call, anything can happen. One function raises an exception, the other returns a special value. The most important is: we can’t rely on this behavior. If xs is empty, this will work:

print(head2(xs))

But this will crash the program:

print(head1(xs))

To avoid some surprises, I would like to know when I’m passing some unexpected argument to a function. In other words: I would like to know when the observable behavior is not reliable, because it depends on the implementation, not on the specification. Of course, I can read the specification, but programmers do not always read carefully the docs.

Imagine if I had a way to insert the specification into the code to get the following effect: when I violate the specification, e.g by passing an empty list to head, I get a warning. That would be a great help to write a correct (i.e. compliant with the specification) program. And that’s where assert enters on the scene:

>>> def head1(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     return xs[0]

And

>>> def head2(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

Now, we have:

>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

And:

>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

Note that head1 throws an AssertionError, not an IndexError. That’s important because an AssertionError is not any runtime error: it signals a violation of the specification. I wanted a warning, but I get an error. Fortunately, I can disable the check (using the -O option), but at my own risks. I will do it a crash is really expensive, and hope for the best. Imagine my program is embedded in a spaceship that travels through a black hole. I will disable assertions and hope the program is robust enough to not crash as long as possible.

This example was only about preconditions, be you can use assert to check postconditions (the return value and/or the state) and invariants (state of a class). Note that checking postconditions and invariants with assert can be cumbersome:

  • for postconditions, you need to assign the return value to a variable, and maybe to store the iniial state of the object if you are dealing with a method;
  • for invariants, you have to check the state before and after a method call.

You won’t have something as sophisticated as Eiffel, but you can however improve the overall quality of a program.


To summarize, the assert statement is a convenient way to detect a this should not happen situation. Violations of the specification (e.g. passing an empty list to head) are first class this should not happen situations. Hence, while the assert statement may be used to detect any unexpected situation, it is a privilegied way to ensure that the specification is fulfilled. Once you have inserted assert statements into the code to represent the specification, we can hope you have improved the quality of the program because incorrect arguments, incorrect return values, incorrect states of a class…, will be reported.


回答 17

格式:assert Expression [,arguments]当assert遇到一条语句时,Python计算该表达式。如果该语句不为true,则会引发异常(assertionError)。如果断言失败,Python将ArgumentExpression用作AssertionError的参数。可以使用try-except语句像其他任何异常一样捕获和处理AssertionError异常,但是如果不处理,它们将终止程序并产生回溯。例:

def KelvinToFahrenheit(Temperature):    
    assert (Temperature >= 0),"Colder than absolute zero!"    
    return ((Temperature-273)*1.8)+32    
print KelvinToFahrenheit(273)    
print int(KelvinToFahrenheit(505.78))    
print KelvinToFahrenheit(-5)    

执行以上代码后,将产生以下结果:

32.0
451
Traceback (most recent call last):    
  File "test.py", line 9, in <module>    
    print KelvinToFahrenheit(-5)    
  File "test.py", line 4, in KelvinToFahrenheit    
    assert (Temperature >= 0),"Colder than absolute zero!"    
AssertionError: Colder than absolute zero!    

format : assert Expression[,arguments] When assert encounters a statement,Python evaluates the expression.If the statement is not true,an exception is raised(assertionError). If the assertion fails, Python uses ArgumentExpression as the argument for the AssertionError. AssertionError exceptions can be caught and handled like any other exception using the try-except statement, but if not handled, they will terminate the program and produce a traceback. Example:

def KelvinToFahrenheit(Temperature):    
    assert (Temperature >= 0),"Colder than absolute zero!"    
    return ((Temperature-273)*1.8)+32    
print KelvinToFahrenheit(273)    
print int(KelvinToFahrenheit(505.78))    
print KelvinToFahrenheit(-5)    

When the above code is executed, it produces the following result:

32.0
451
Traceback (most recent call last):    
  File "test.py", line 9, in <module>    
    print KelvinToFahrenheit(-5)    
  File "test.py", line 4, in KelvinToFahrenheit    
    assert (Temperature >= 0),"Colder than absolute zero!"    
AssertionError: Colder than absolute zero!    

回答 18

def getUser(self, id, Email):

    user_key = id and id or Email

    assert user_key

可用于确保在函数调用中传递参数。

def getUser(self, id, Email):

    user_key = id and id or Email

    assert user_key

Can be used to ensure parameters are passed in the function call.


回答 19

>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)

>>> #first we try without assert
>>>if test_us == True:
    print("YES! I am right!")
else:
    print("I am Wrong, but the program still RUNS!")

I am Wrong, but the program still RUNS!


>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    assert test_us
AssertionError
>>> 
>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)

>>> #first we try without assert
>>>if test_us == True:
    print("YES! I am right!")
else:
    print("I am Wrong, but the program still RUNS!")

I am Wrong, but the program still RUNS!


>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    assert test_us
AssertionError
>>> 

回答 20

基本上,assert关键字的含义是,如果条件不成立,则通过assertionerror进行处理,否则例如在python中继续进行。

代码1

a=5

b=6

assert a==b

输出:

assert a==b

AssertionError

代码2

a=5

b=5

assert a==b

输出:

Process finished with exit code 0

Basically the assert keyword meaning is that if the condition is not true then it through an assertionerror else it continue for example in python.

code-1

a=5

b=6

assert a==b

OUTPUT:

assert a==b

AssertionError

code-2

a=5

b=5

assert a==b

OUTPUT:

Process finished with exit code 0