【问题标题】:python module variable not mutable as a function_defaultpython模块变量作为function_default不可变
【发布时间】:2013-10-31 20:26:28
【问题描述】:

我需要通过更改名为 process.py 的应用程序模块头部的默认值来对 python 模块进行单元测试。声明的默认值是一个固定的 int。我可以将其更改为使用 os.environ 中的其他内容,但我希望简单地分配全局,但显然我缺少对“def”的一些理解。

process.default_timeout_secs = 2

# --name: process

default_timeout_secs = 120

def call_process(cmd, timeout=default_timeout_secs):
    print 'run:', cmd, 'timeout:', timeout
    ...



# --name: test_process
from nose.tools import *
import process

@ raises(TimeoutExpired)
def test_process_run_modified_default():
    process.default_timeout_secs = 5
    run(sleep 10)

我从其他帖子中了解到,导入模块时,default_timeout_secs 的 process.call_process.func_defaults 值不是模块顶部的值。如何更改函数中使用的默认值?

process.default_timeout_secs = 5 process.call_process.func_globals['default_timeout'] 5 process.call_process.func_defaults (120)

Out[21]: 5
>>> process.call_process(cmd)

Out[22]: call_process: cmd= sleep 2 timeout= 120       <----- 120? 
         Executing cmd sleep 2 verbose=True

输出应显示异常 TimoutExpired。

【问题讨论】:

    标签: python unit-testing import module global


    【解决方案1】:

    函数默认值在定义时评估,而不是在调用时评估(参见"Least Astonishment" and the Mutable Default Argument)。

    访问和修改函数默认值的唯一方法是through its __defaults__ property(旧版本为func_defaults):

    >>> def f(a=5):
    ...     return a
    >>> f.__defaults__
    (5,)
    >>> f.__defaults__ = (99,)
    >>> f()
    99
    

    请注意,__defaults__ 是一个元组,因此您不能单独分配其成员,但可以将其作为一个整体分配。

    【讨论】:

      【解决方案2】:
      d = list(process.call_process.func_defaults)
      
      In [10]: d
      Out[10]: [True, True, 120]
      
      In [11]: d[-1] = 5
      
      In [12]: d
      Out[12]: [True, True, 5]
      
      In [13]: t = tuple(d)
      
      In [14]: t
      Out[14]: (True, True, 5)
      
      In [15]: process.call_process.func_defaults = t
      process.call_process('sleep 8')
      
      call_process(cmd, verbose, shell, timeout, **kwargs)
           94         except:
           95             print(str(c.getName()) + 'running cmd "'+ cmd+ '" could not be terminated')
      ---> 96         raise TimeoutExpired('calling '+cmd)
           97     else:
           98         return c.response
      
      TimeoutExpired: calling sleep 8
      
      In [17]: call_process result: 0 :--:-None-:
      

      【讨论】:

        【解决方案3】:

        关于更改默认值以进行测试的原始问题,您可能想要使用一个可变对象的字典。 See my answer there了解详情。

        【讨论】:

          猜你喜欢
          • 2011-06-25
          • 2015-09-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多