Reputation: 17621
I am trying to assign a function to another function the left hand side of the assignment is available to me as a String. For example the body of the method I am looking for is
def change_function_defintion(name_of_function = 'module1.function1'
, function_object):
# Can I do eval(name_of_function) = function_object ? will that work?
pass
Questions:
Upvotes: 3
Views: 5370
Reputation: 26333
Python function decorator
First, the notion you are talking about is the notion of function decorator. A function decorator is applied to a function definition by placing it on the line before that function definition begins (symbol @
). It is a tool to modify the behavior of a function, or do operate composition of functions. Here is an example
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()"
I i run
func1()
func2()
i get
Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2
Python unittest.mock.patch()
patch acts as a function decorator, class decorator or a context manager. Inside the body of the function or with statement, the target is patched with a new object. When the function/with statement exits the patch is undone.
Patch lets you modify the function behavior within the with
statement.
Here is an example where patch() is used as a context manager with a with
statement.
>>> 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)
Upvotes: 1
Reputation: 5713
I think the following will do what you want (but you might want more robust parsing):
def set_named_fun(funname, fun) :
import sys
modname, funname = funname.rsplit('.')
mod = sys.modules[modname]
setattr(mod, funname, fun)
The assumptions here are:
The two assumptions are slightly in tension. There must be a great many cases where you can simply do:
import legend
legend.monkey = lambda : "great sage, equal of heaven"
Upvotes: 1
Reputation: 15990
My approach:
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)
Now the longer rant:
That approach will probably work, if module1 is already imported in the local namespace, for instance, you can do something like:
>>> a = eval('str')
>>> a
<type 'str'>
>>> a(123)
'123'
In the context of mocking for unit tests, there might be a better way of doing so.
You can check here: http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy#MockTestingTools for some libraries that will allow you to have more control around mocking objects in your unit tests.
EDIT:
You can do something like this, to dynamically import modules:
>>> import importlib
>>> my_mod = importlib.import_module('mymodule1')
Then, you can access the available functions inside the module, or get them via eval/getattr:
my_function = getattr(my_mod,'somefunction')
Of, if you want to swap that function to something else:
my_mod.functionName = newFunction
Upvotes: 1
Reputation: 48335
There are some problems with mocking and you might consider a different testing approach if possible:
Upvotes: 1
Reputation: 20527
I think it would be better to use a mocking library like Mock. Using patch
you can change the function's behaviour within the scope of a context manager or a function and have it change back to normal afterwards. For example:
from mock import patch
with patch('module1.function1') as function1:
function1.side_effect = function_object
# Do stuff
if function1
is called inside the with
block it will be replaced with function_object
.
Similarly, patching within a function:
@patch('module1.function1')
def my_test(function1):
function1.side_effect = function_object
# Do stuff
Upvotes: 5
Reputation: 187
Can use "getattr" to get the function using the string name of the function (A function is an object). Then you can change the name and call / call something else (original named function) in the new named call.
Upvotes: 0