2010-07-28 2 views
11

Я пытаюсь передать имя функции в другую функцию в качестве аргумента, но получаю сообщение об ошибке: «Объект TypeError: 'str' не может быть вызван». Вот упрощенный пример проблемы:Python: Передача имени функции в качестве аргумента в функции

def doIt(a, func, y, z): 
    result = z 
    result = func(a, y, result) 
    return result 

def dork1(arg1, arg2, arg3): 
    thing = (arg1 + arg2)/arg3 
    return thing 

def dork2(arg1, arg2, arg3): 
    thing = arg1 + (arg2/arg3) 
    return thing 

Когда я называю Doit так:

var = 'dork1' 
ned = doIt(3, var, 4, 9) 
print (ned) 

я получаю:

Traceback (most recent call last): 
    File "<pyshell#9>", line 1, in <module> 
    ned = doIt(3, var, 4, 9) 
    File "<pyshell#2>", line 3, in doIt 
    result = func(a, y, result) 
TypeError: 'str' object is not callable 
+1

Rock on! globals() работал! Спасибо за вашу помощь. – Desmond

+10

Noooo! Слушай Алекс Мартелли! Он WROTE python в двух словах! Не прибегайте к использованию уродливого взлома, который редко бывает когда-либо, чтобы сделать что-то, что вы можете сделать чисто! Научитесь правильно использовать язык! – jeremiahd

ответ

24

Если вы хотите передать имя функции , как вы сказали, и вы делаете, конечно, вы не можете назвать это - почему бы один «назвать имя»? Это бессмысленно.

Если вы хотите назвать это, передать саму функцию, то есть, самым решительным образом не

var = 'dork1' 

а

var = dork1 

без кавычек!

Редактировать: ОП задается вопросом (!) Как получить объект функции с именем функции (в виде строки). Как это происходит, я просто показал, как сделать это в учебнике я преподавал в OSCON (из которого я только что вернулся) - получить слайды из here и смотрите на странице 47, «Ленивый загрузкой обратных вызовов»:

class LazyCallable(object): 
  def __init__(self, name): 
    self.n, self.f = name, None 
  def __call__(self, *a, **k): 
    if self.f is None: 
      modn, funcn = self.n.rsplit('.', 1) 
      if modn not in sys.modules: 
        __import__(modn) 
      self.f = getattr(sys.modules[modn], 
         funcn) 
    self.f(*a, **k) 

Итак, вы могли бы пройти LazyCallable('somemodule.dork1') и жить счастливо. Если вам не нужно иметь дело с модулем, конечно (какая странная архитектура должна подразумевать!), Легко настроить этот код.

+2

Десмонд может использоваться для передачи имени функции «php-style», которая помещает имя функции в строку, а затем передает ее и вызывает ее, где она, по-видимому, получает значение или что-то еще. * Дрожь *. – jeremiahd

4

Не передавайте имя функции.

Передача функции.

fun = dork1 
ned = doIt(3, fun, 4, 9) 
print (ned) 
2
var = 'dork1' 
ned = doIt(3, var, 4, 9) 
print (ned) 

В этом примере var является строкой. Функция doIt «вызывает» свой второй аргумент (для которого вы проходите var). Передайте функцию вместо этого.

+0

Что делать, если я получаю dork1 из значения словаря, которое хранится в виде строки? Как преобразовать его в функцию «объект» (я знаю, что здесь не правильная терминология), а не как строка, чтобы я мог правильно ее передать? – Desmond

+0

Проверьте функцию 'eval()': http://docs.python.org/library/functions.html#eval – advait

+1

. Ваше значение dict должно быть просто объектом функции: funcs = {'first': dork1, 'second': dork2 '} do ** не ** проверить функцию eval, если вы не уверены, что это необходимо. и даже тогда вам, вероятно, все равно не нужно. Существует почти наверняка лучшее решение. – jeremiahd

0

Функции являются первоклассными объектами в python. Сделайте это:

var = dork1 

Если вы должны передать строку, например, пользовательский ввод, затем:

globals()[var] 

будет искать объект функции.

1

Вы, вероятно, не должны делать это, но вы можете получить функцию с помощью Eval()

, например, использовать Len,

eval("len")(["list that len is called on"]) 
1

Я был взволнован, чтобы найти это, и я не» Не знаю, было ли это ответ. Мое решение этой проблемы заключается в следующем:

def doIt(func, *args): 
    func_dict = {'dork1':dork1,'dork2':dork2} 
    result = func_dict.get(func)(*args) 
    return result 

def dork1(var1, var2, var3): 
    thing = (float(var1 + var2)/var3) 
    return thing 

def dork2(var1, var2, var3): 
    thing = float(var1) + (float(var2)/var3) 
    return thing 

Это можно выполнить следующим образом:

func = 'dork2' 
ned = doIt(func,3, 4, 9) 
print ned 
+0

Хорошее обходное решение, но это не будет служить общим решением проблемы OP. –

0
def run_function(function_name): 
    function_name() 

В этом примере, вызов run_function(any_function) будет вызывать any_function().

+0

Как вы можете проверить, существует ли функция? –

+0

Вызов функции вызывает 'NameError' или' AttributeError', если функция не существует. Просто поймайте эти исключения. – Zenadix

Смежные вопросы