Python将函数分配给另一个函数

时间:2013-05-09 10:13:48

标签: python python-2.7

我正在尝试将一个函数分配给另一个函数,赋值的左侧可以作为String使用。例如,我正在寻找的方法的主体是

def change_function_defintion(name_of_function = 'module1.function1'
       , function_object):
    # Can I do eval(name_of_function) = function_object ? will that work?
    pass

问题:

  1. 我如何实现这一目标?显然,如果我调用上面的方法,然后调用module.function1,我希望能够选择新函数。
  2. 我在单元测试的环境中这样做,即模拟几个函数,运行测试然后基本上“取消”它们。上述方法有问题吗?

6 个答案:

答案 0 :(得分:3)

我认为使用像Mock这样的模拟库会更好。使用patch,您可以在上下文管理器或函数的范围内更改函数的行为,然后将其更改回正常状态。例如:

from mock import patch

with patch('module1.function1') as function1:
    function1.side_effect = function_object
    # Do stuff

如果在function1块内调用with,则会将其替换为function_object

同样,在函数内修补:

@patch('module1.function1')
def my_test(function1):
    function1.side_effect = function_object
    # Do stuff

答案 1 :(得分:1)

我的方法:

import importlib

def change_function_defintion(name_of_function = 'module1.function1'
   , function_object):
   my_mod = importlib.import_module('module1')
   setattr(my_mod, function1, function_object)

现在更长的咆哮:

这种方法可能会有效,如果已经在本地命名空间中导入了module1 ,例如,你可以这样做:

>>> a = eval('str')
>>> a
<type 'str'>
>>> a(123)
'123'

在模拟单元测试的环境中,可能有更好的方法。

你可以在这里查看: 对于某些库,http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy#MockTestingTools允许您在单元测试中对模拟对象进行更多控制。

编辑:

你可以这样做,动态导入模块:

>>> import importlib
>>> my_mod = importlib.import_module('mymodule1')

然后,您可以访问模块内的可用函数,或通过eval / getattr获取它们:

my_function = getattr(my_mod,'somefunction')

如果您想将该功能交换为其他功能:

my_mod.functionName = newFunction

答案 2 :(得分:1)

模拟存在一些问题,如果可能,您可以考虑使用不同的测试方法:

答案 3 :(得分:1)

我认为以下内容可以满足您的需求(但您可能需要更强大的解析):

def set_named_fun(funname, fun) :
    import sys
    modname, funname =  funname.rsplit('.')
    mod = sys.modules[modname]
    setattr(mod, funname, fun)

这里的假设是:

  • 拥有该功能的模块已导入,
  • 您需要将目标函数称为完全限定名称

这两个假设略有紧张。必须有很多情况下你可以做到:

import legend
legend.monkey = lambda : "great sage, equal of heaven"

答案 4 :(得分:1)

Python函数装饰器

首先,您所谈论的概念是函数装饰器的概念。函数装饰器通过在函数定义开始之前将其放置在行上而应用于函数定义(符号@)。它是一种修改函数行为或操作函数组合的工具。这是一个例子

class entryExit(object):

    def __init__(self, f):
        self.f = f

    def __call__(self):
        print "Entering", self.f.__name__
        self.f()
        print "Exited", self.f.__name__

@entryExit # decorator
def func1(): # decorated function
    print "inside func1()"

@entryExit
def func2():
    print "inside func2()"

我跑

func1()
func2()

我得到了

Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2

Python unittest.mock.patch()

  

补丁充当函数装饰器,类装饰器或上下文   经理。在函数体内或带语句,目标   用新对象修补。当函数/ with语句退出时   修补程序已撤消。

Patch允许您修改with语句中的函数行为。

这是一个示例,其中patch()用作具有with语句的上下文管理器。

>>> with patch.object(ProductionClass, 'method', return_value=None) 
  as mock_method:
...     thing = ProductionClass()
...     thing.method(1, 2, 3)
...
>>> mock_method.assert_called_once_with(1, 2, 3)

答案 5 :(得分:0)

可以使用“getattr”来使用函数的字符串名称来获取函数(函数是一个对象)。然后你可以在新的命名调用中更改名称并调用/调用其他内容(原始命名函数)。