我有以下函数,我使用 doctest 进行单元测试。
from collections import deque
def fill_q(histq=deque([])):
"""
>>> fill_q()
deque([1, 2, 3])
>>> fill_q()
deque([1, 2, 3])
"""
if histq:
assert(len(histq) == 0)
histq.append(1)
histq.append(2)
histq.append(3)
return histq
if __name__ == "__main__":
import doctest
doctest.testmod()
第一种情况通过,但第二次调用 fill_q 失败,但代码相同:
**********************************************************************
File "trial.py", line 7, in __main__.fill_q
Failed example:
fill_q()
Exception raised:
Traceback (most recent call last):
File "/usr/lib/python2.7/doctest.py", line 1289, in __run
compileflags, 1) in test.globs
File "<doctest __main__.fill_q[1]>", line 1, in <module>
fill_q()
File "trial.py", line 11, in fill_q
assert(len(histq) == 0)
AssertionError
**********************************************************************
1 items had failures:
1 of 2 in __main__.fill_q
***Test Failed*** 1 failures.
看起来 doctest 重新使用了第一次测试调用中的局部变量 histq
,为什么要这样做?这是非常愚蠢的行为(假设不是我在这里疯狂做某事)。
最佳答案
问题不在于 doctest
,而是您在 def fill_q(histq=deque([]))
中使用的默认参数。与此类似:
>>> from collections import deque
>>>
>>> def fill_q(data=deque([])):
... data.append(1)
... return data
...
>>> fill_q()
deque([1])
>>> fill_q()
deque([1, 1])
>>> fill_q()
deque([1, 1, 1])
当您使用可变对象作为默认值(例如列表或字典)时,就会发生这种看似奇怪的行为。它实际上使用同一个对象:
>>> id(fill_q())
4485636624
>>> id(fill_q())
4485636624
>>> id(fill_q())
4485636624
<小时/>
为什么?
当且仅当执行它们所属的 def
语句时,默认参数值始终会被求值 [ ref ].
如何避免此错误:
使用 None
作为默认参数,或用于任意对象:
my_obj = object()
def sample_func(value=my_obj):
if value is my_obj:
value = expression
# then modify value
<小时/>
何时使用它?:
全局名称的本地重新绑定(bind):
import math def fast_func(sin=math.sin, cos=math.cos):
可用于内存(例如,使某些递归运行得更快)
关于Python doctest执行上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12717266/