Покажчик функції Python


75

У мене є ім'я функції, яке зберігається у такій змінній:

myvar = 'mypackage.mymodule.myfunction'

і я зараз хочу зателефонувати до своєї функції таким чином

myvar(parameter1, parameter2)

Який найпростіший спосіб цього досягти?


4
Чому б не зберегти саму функцію? myvar = mypackage.mymodule.myfunctionнабагато чистіше.
ironfroggy

1
З коментаря нижче: «Це має бути рядок, оскільки в місці, де воно визначено, додаток не знає потрібної функції, оскільки це загальний додаток.» - schneck
badp

Відповіді:


112
funcdict = {
  'mypackage.mymodule.myfunction': mypackage.mymodule.myfunction,
    ....
}

funcdict[myvar](parameter1, parameter2)

1
Цікаво, який тут показник продуктивності, якщо функцію збиралися викликати багато разів (у циклі, рекурсії тощо)?
zanlok

5
Посилання вже вирішено, тому лише пошук у дикті займає більше часу, ніж виклик локальної функції. І навіть це можна пом’якшити, лише один раз піднявши очі.
Ігнасіо Васкес-Абрамс

Що це за "mypackage.mymodule.myfunction"? Де я можу прочитати більше про це?
Орвар Корвар

@OrvarKorvar: Замініть назви та посилання на ваш вибір.
Ігнасіо Васкес-Абрамс

Ах, тепер я розумію. fundict - це словник.
Орвар Корвар,

41

Набагато приємніше мати можливість просто зберігати саму функцію, оскільки це першокласні об’єкти в python.

import mypackage

myfunc = mypackage.mymodule.myfunction
myfunc(parameter1, parameter2)

Але якщо вам потрібно імпортувати пакет динамічно, то ви можете досягти цього за допомогою:

mypackage = __import__('mypackage')
mymodule = getattr(mypackage, 'mymodule')
myfunction = getattr(mymodule, 'myfunction')

myfunction(parameter1, parameter2)

Однак майте на увазі, що вся ця робота стосується будь-якої сфери, в якій ви зараз перебуваєте. Якщо ви якось не дотримуєтесь їх, ви не можете розраховувати на те, що вони залишаться поруч, якщо залишите локальну сферу.


15
def f(a,b):
    return a+b

xx = 'f'
print eval('%s(%s,%s)'%(xx,2,3))

ВИХІД

 5

Я дам голос проти, щоб протидіяти цьому. Це може бути не найкращим рішенням, я вважаю, що це корисна відповідь, оскільки воно показує повний, робочий приклад.
Брайан Оклі

5
@zanlok Так це! :-) тоді я цього не знав.
Pratik Deoghare

@PratikDeoghare iam для початківців у python, чи можете ви пояснити, що (xx = 'f') робить, дякую.
RaHuL

9

Найпростіший

eval(myvar)(parameter1, parameter2)

У вас немає функції "покажчик". У вас є функція "ім'я".

Хоча це працює добре, у вас буде велика кількість людей, які говорять вам, що це "небезпечно" або "небезпека безпеки".


1
"небезпечно": якщо myvar походить від вводу користувача, так :)
Федеріко А. Рампоні,

1
@schneck, чому тоді це, можливо, повинно бути рядком?
Mike Graham

2
@schneck: Якщо eval ('рядок') не дає правильної функції, то ваше запитання неповне. Ви пропустили щось вирішальне. Ви можете спробувати опублікувати то , що робить роботу разом з докладним повідомленням про помилку про те , що не працює.
S.Lott

2
@Derrick Turn, @Truptych: Вони мали б рацію лише в тому випадку, якщо рядок походить від зловмисного соціопата. Користувальницькі дані користувачів, які не підлягають автентифікації в Інтернеті, швидше за все, включатимуть злісних соціопатів. Більшість всього іншого, як правило, не стосується зловмисних соціопатів, зменшуючи ризик безпеки до точно такого ж ризику, як хтось видаляє весь вихідний код програми.
S.Lott

6
@schneck, я не розумію, що ви маєте на увазі під словом "оскільки це загальний додаток", що може означати тут. Якщо ви визначили це як рядковий літерал, ви вже знаєте про це достатньо, що вам не потрібно це робити.
Mike Graham



2

eval(compile(myvar,'<str>','eval'))(myargs)

compile (..., 'eval') допускає лише один вираз, так що після виклику не може бути довільних команд, або буде SyntaxError. Тоді крихітний фрагмент перевірки може принаймні обмежити вираз до чогось, що у вас є, наприклад, тестування на "mypackage" для початку.


2

Я зіткнувся з подібною проблемою під час створення бібліотеки для обробки автентифікації. Я хочу, щоб власник програми, який використовує мою бібліотеку, мав можливість зареєструвати зворотний виклик у бібліотеці для перевірки авторизації щодо груп LDAP, в яких знаходиться особа, що пройшла аутентифікацію. Конфігурація передається як файл config.py, який імпортується та містить dict усі параметри конфігурації.

Я отримав це для роботи:

>>> class MyClass(object):
...     def target_func(self):
...         print "made it!"
...    
...     def __init__(self,config):
...         self.config = config
...         self.config['funcname'] = getattr(self,self.config['funcname'])
...         self.config['funcname']()
... 
>>> instance = MyClass({'funcname':'target_func'})
made it!

Чи існує пітонічний спосіб зробити це?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.