Имена на динамични функции на Python

Търся по-добър начин за извикване на функции въз основа на променлива в Python срещу използване на if/else оператори като по-долу. Всеки код на състояние има съответна функция

if status == 'CONNECT':
    return connect(*args, **kwargs)
elif status == 'RAWFEED':
    return rawfeed(*args, **kwargs)
elif status == 'RAWCONFIG':
    return rawconfig(*args, **kwargs)
elif status == 'TESTFEED':
    return testfeed(*args, **kwargs)
...

Предполагам, че това ще изисква някаква фабрична функция, но не съм сигурен за синтаксиса


person drjeep    schedule 25.03.2009    source източник


Отговори (8)


Каноничният начин да направите това е да използвате речник за емулиране на switch или if/elif. Ще намерите няколко въпроса за подобни проблеми тук на SO.

Поставете вашите функции в речник с вашите кодове за състояние като ключове:

funcs = {
    'CONNECT': connect,
    'RAWFEED': rawfeed,
    'RAWCONFIG' : rawconfig,
    'TESTFEED': testfeed
}
funcs[status](*args, **kwargs)
person Community    schedule 25.03.2009
comment
func['status'] ще предизвика KeyError - person SilentGhost; 25.03.2009
comment
Мисля, че това е безопасен начин, предизвиква изключение, когато status е неочаквано име на метод. - person Andrew T; 25.03.2009
comment
DRY рядко се прилага в случаи като този. Първоначалният списък с функции може да има имена, подобни на низове; но това често води до по-сложни взаимоотношения. - person S.Lott; 25.03.2009
comment
@S.Lott: заглавието на въпроса гласи „имена на динамични функции“. Това е статично картографиране. - person vartec; 25.03.2009
comment
@goodrone: и какво мислиш, че прави, когато използваш getattr? освен това има лесен начин за предоставяне на метод по подразбиране. - person SilentGhost; 25.03.2009
comment
Това не е каноничният питоничен начин за диспечиране на функции. getattr е каноничният метод в този случай - person hasen; 25.03.2009
comment
Бих използвал този метод, когато променливата на състоянието не е външна, т.е. от уеб формуляр или нещо подобно, или ако функциите могат да бъдат преименувани на нещо различно от версия с малки букви на низа на състоянието - можете също да спорите, че това е по-ясно (и следователно повече Pythonic). Въпреки това бих бил по-склонен да използвам метода getattr, когато списъкът с функции е голям или се променя по размер. - person Brendan; 07.12.2010

може да намерите getattr полезен, предполагам

import module
getattr(module, status.lower())(*args, **kwargs)
person SilentGhost    schedule 25.03.2009
comment
Благодаря за този пример, не разбрах, че getattr() също работи върху модули - person drjeep; 25.03.2009

ако приемем, че тези функции принадлежат към някакъв модул:

import module
return getattr(module, status.lower()).__call__(*args, **kwargs)
person vartec    schedule 25.03.2009

изглежда, че можете да използвате getattr по малко по-различен (според мен по-елегантен начин)

import math
getattr(math, 'sin')(1)

или ако функцията е импортирана, както е показано по-долу

from math import sin

sin вече е в пространството на имената, така че можете да го наричате с

vars()['sin'](1)
person to-chomik    schedule 25.03.2009

Известно подобрение на отговора на SilentGhost:

globals()[status.lower()](*args, **kwargs)

ако искате да извикате функцията, дефинирана в текущия модул.

Въпреки че изглежда грозно. Бих използвал решението с речник.

person Eugene Morozov    schedule 25.03.2009

Вижте това: getattra като диспечер на функции

person hasen    schedule 25.03.2009
comment
Връзката е мъртва, резултатът намалява. Съжалявам за това. - person Drachenfels; 11.05.2012

Срещнах същия проблем преди. Разгледайте този въпрос, мисля, че е това, което търсите.

Изявления за речник или If

Надявам се това да е полезно

Eef

person RailsSon    schedule 25.03.2009

някои промени от предишния:

funcs = {
'CONNECT': connect,
'RAWFEED': rawfeed,
'RAWCONFIG' : rawconfig,
'TESTFEED': testfeed
}

func = funcs.get('status')
if func:
    func(*args, **kwargs)
person linjunhalida    schedule 25.03.2009
comment
не, не става. това е същата грешка, която heikogerlach имаше в началото. - person SilentGhost; 25.03.2009
comment
Замених „статус“ с променливата, така че предполагам, че технически не е така. Интересувам се повече от метода, отколкото от семантиката - person drjeep; 25.03.2009