2013-05-09 4 views
1

Я пытаюсь назначить функцию другой функции, левая часть задания доступна мне как строка. Например, тело метода я ищу,Python назначает функцию другой функции

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. Я делаю это в контексте модульного тестирования. Я выполняю несколько функций, запускаю тест и затем в основном «отключаю» их. Существуют ли какие-либо проблемы с этим подходом?
+1

Возможный дубликат [Как динамически загружать класс Python] (http: // stackoverflow.com/questions/547829/how-to-dynamically-load-a-python-class) –

+2

Подобно классам, функции являются первоклассными объектами. Вы можете динамически импортировать модуль, а затем получить функцию как атрибут. –

+0

Обратите внимание, что это определенно отличается от вопроса «Как динамически загружать класс Python». Я явно просил о каких-либо улучшениях/проблемах с использованием метода eval и совершенно справедливо указал на структуру MOCK для python, которая включена по умолчанию в python. 3.3. –

ответ

2

Я думаю, что было бы лучше использовать насмешливую библиотеку, такую ​​как 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 
+0

Это то, что я закончил делать. Благодаря !! –

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 для некоторых библиотек, которые позволят вам контролировать контроль над насмешками в ваших модульных тестах.

EDIT:

Вы можете сделать что-то подобное, чтобы динамически импортировать модули:

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

Тогда, вы можете получить доступ к доступным функциям внутри модуля, или получить их через Eval/GetAttr:

my_function = getattr(my_mod,'somefunction') 

Of, если вы хотите поменять эту функцию на что-то другое:

my_mod.functionName = newFunction 
+0

Но для этого требуется, чтобы 'module1' был импортирован уже в локальное пространство имен. –

0

Может использовать «getattr» для получения функции с использованием имени строки функции (функция - это объект). Затем вы можете изменить имя и вызвать/вызвать что-то другое (оригинальная именованная функция) в новом именованном вызове.

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" 
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.

>>> 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) 
Смежные вопросы