Vă mulțumim pentru susținere

Apelarea unei funcții a unui modul utilizând numele său (un șir)

Care este cel mai bun mod de a merge despre apelarea unei funcții date unui șir cu numele funcției într-un program Python. De exemplu, să presupunem că am un modul foo și am un șir al cărui conținut este "bar" . Care este cel mai bun mod de a apela foo.bar () ?

Trebuie să obțin valoarea returnată a funcției, de aceea nu folosesc doar codul eval . M-am gândit cum să o fac folosind codul eval pentru a defini o funcție temporară care returnează rezultatul apelului funcției, dar sper că există un mod mai elegant pentru a face acest lucru.

0
adăugat editat

9 răspunsuri

Soluția lui Patrick este probabil cea mai curată. Dacă trebuie să ridicați dinamic modulul, puteți să-l importați ca:

module = __import__('foo')
func = getattr(module, 'bar')
func()
0
adăugat
@ glarrain Atâta timp cât sunteți în regulă doar cu suportul 2.7 și mai sus.
adăugat autor Xiong Chiamiov
@cowlinator Da, 3.6 face parte din "2.7 și mai sus", atât în ​​semantica de versiune strictă, cât și în data lansării (a venit cam șase ani mai târziu). De asemenea, nu a existat timp de trei ani după comentariul meu. ;) În ramura 3.x, modulul a fost în jur de la 3.1. 2.7 și 3.1 sunt acum destul de vechi; veți găsi în continuare servere agățate în jurul valorii de numai suportul 2.6, dar probabil că merită să avem importlib sfatul standard în zilele noastre.
adăugat autor Xiong Chiamiov
@Xiong Chaimiov, importlib.import_module este acceptat în 3.6. Consultați docs.python.org/3.6/library/…
adăugat autor cowlinator
Utilizați importlib.import_module . Documentele oficiale spun despre __ import __ : "Aceasta este o funcție avansată care nu este necesară în programarea zilnică Python, spre deosebire de importlib.import_module ()". docs.python.org/2/library/functions.html#__import__
adăugat autor glarrain
Nu înțeleg ultimul comentariu. __import__ are propriul său drept, iar următoarea propoziție din documentele menționate spune: "Utilizarea directă a __import __ () este rară, cu excepția cazurilor în care doriți să importați un modul al cărui nume este cunoscut numai la runtime". Deci: +1 pentru răspunsul dat.
adăugat autor hoffmaje

nici unul din ceea ce mi sa sugerat nu ma ajutat. Dar am descoperit asta.

.__getattribute__()() 

Eu folosesc Python 2.66

Sper că acest lucru vă ajută

0
adăugat
În ce aspect este mai bine decât getattr ()?
adăugat autor V13

Pentru ce merită, dacă trebuia să treci numele funcției (sau clasei) și numele aplicației ca șir, atunci ai putea face acest lucru:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)
0
adăugat
Doar puțin mai generic este handler = getattr (sys.modules [__ name__], myFnName)
adăugat autor lony

Având un șir, cu o cale completă de pioni la o funcție, așa am făcut pentru a obține rezultatul funcției menționate:

import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()
0
adăugat
Acest lucru ma ajutat. O versiune ușoară a funcției __ import __ .
adăugat autor Pankaj Bhambhani
Soluție potrivită!
adăugat autor Nebulosar
locals()["myfunction"]()

sau

globals()["myfunction"]()

locals returns a dictionary with a current local symbol table. globals returns a dictionary with global symbol table.

0
adăugat
@Joelmob există o altă modalitate de a obține un obiect prin șir din spațiul de nume rădăcină?
adăugat autor Nick T
Această metodă cu globali / localnici este bună dacă metoda pe care trebuie să o apelați este definită în același modul pe care îl apelați.
adăugat autor Joelmob
@NickT Sunt doar constient de aceste metode, nu cred ca exista altele care implinesc aceeasi functie ca acestea, cel putin nu ma pot gandi la un motiv pentru care ar trebui sa existe mai mult.
adăugat autor Joelmob
Am un motiv pentru tine (de fapt ceea ce ma condus aici): Modulul A are o funcție F care trebuie să numească o funcție după nume. Modulul B importă modulul A și invocă funcția F cu o cerere de a apela funcția G, care este definită în modulul B. Această chemare nu reușește deoarece, aparent, funcția F rulează numai cu globalele definite în modulul F - globali () ['G'] = Niciuna.
adăugat autor David Stein

Presupunând modul foo cu metoda bar :

import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()

În ceea ce privește acest lucru, liniile 2 și 3 pot fi comprimate la:

result = getattr(foo, 'bar')()

dacă acest lucru are mai mult sens pentru cazul dvs. de utilizare. Puteți folosi getattr în acest mod pe metodele legate de instanțe de clasă, pe metode la nivel de modul, metodele de clasă ... lista continuă.

0
adăugat
Nimeni altcineva nu multumeste acestui raspuns bun, de dragul valorii actuale.
adăugat autor Coolio2654
Acest lucru nu funcționează cu funcțiile care utilizează un decorator. getattr returnează funcția externă
adăugat autor azmeuk
hasattr sau getattr pot fi folosite pentru a determina dacă o funcție este definită. Am avut o mapare de baze de date (eventType și handling functionName) și am vrut să fiu sigur că niciodată nu am "uitat" să definească un handler de evenimente în Python
adăugat autor Shaun
Meh. Am petrecut 10 minute încercând variante de foo.getattr ('bar') și foo.get_attr ('bar') .
adăugat autor Eric Duminil
A se vedea și răspunsul oferit de @sastanin dacă vă interesează doar de exemplu despre funcțiile modulului dvs. local / curent.
adăugat autor NuSkooler
Notă: cool +1, acest lucru ma făcut să înțeleg încă o dată că în Python totul este un obiect. În consecință, funcționează și cu variabile, puteți accesa variabilele unui modul ca variabilele altor obiecte.
adăugat autor tuned
@akki Da, dacă sunteți în modulul foo , puteți folosi globals () pentru a face acest lucru: methodToCall = global ) [ 'bar']
adăugat autor Ben Hoyt
@ PatrickJohnmeyer Nu exclud niciodată modelele / paradigmele ... De aceea, am pus o întrebare în loc să fac o declarație pătură. Există o mulțime de repercusiuni negative pentru utilizarea acestui model în mod excesiv ... care (cel puțin în experiența mea) este comună.
adăugat autor KeatsKelleher
Puteți face acest lucru, dar ar trebui să vă? Cum veți găsi toate instanțele funcției dvs. de apel atunci când baza de cod devine mare? Nu este nimic de înfruntat și niciun IDE nu va găsi acea referință. Asta face ca acest tip de apel dinamic să fie foarte supărător. Nu este mai frumos pentru colegii dvs. să fie explicit, oricum? Mai puțin codul nu înseamnă întotdeauna mai ușor de citit.
adăugat autor KeatsKelleher
Acest lucru funcționează dacă cunoașteți deja numele modulului. Cu toate acestea, dacă doriți ca utilizatorul să furnizeze numele modulului ca șir, acest lucru nu va funcționa.
adăugat autor Blairg23
@KeatsKelleher, deoarece nu cunoaștem cazul de utilizare, doar întrebarea, tot ce pot spune în mod credibil este că există multe cazuri de utilizare în care punctul dvs. de vedere se aplică și unele care nu. Este comun și rezonabil să faceți astfel de lucruri în motoare de reguli, DSL-uri, scripturi în aplicații etc., în care codul pe care îl scrieți există pentru a rula un alt cod. Există, probabil, numeroase alte "bune" momente pentru a face acest lucru pe care nu mă gândesc acum. Deci, ar trebui să facem asta? Răspunsul, ca și în cazul majorității limbilor în majoritatea limbilor,
adăugat autor Patrick Johnmeyer
Dacă trebuie să evitați ca o excepție să nu fie o excepție de tip "callable", puteți folosi formatul cu trei argumente de getattr: getattr (foo, 'bar', lambda: None). Îmi cer scuze pentru formatare; aplicația Android stackexchange este aparent teribilă.
adăugat autor geekofalltrades
Dacă aveți structuri profunde, sintaxa următoare ar putea fi utilă: de la functools import reduce reduce (getattr, "a.b.c.d.e.f.g" .split ('.'), DeepStructure)
adăugat autor Robert Parcus
Acesta este un răspuns foarte util, cumpărare nu am putut lucra atunci când modulul foo este modulul actual în sine. Știe cineva cum să facă asta?
adăugat autor akki

Doar o simplă contribuție. Dacă clasa de care avem nevoie pentru instanță este în același fișier, putem folosi ceva de genul:

# Get class from globals and create an instance
m = globals()['our_class']()

# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')

# Call it
func()

De exemplu:

class A:
    def __init__(self):
        pass

    def sampleFunc(self, arg):
        print('you called sampleFunc({})'.format(arg))

m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')

# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')

Și dacă nu o clasă:

def sampleFunc(arg):
    print('you called sampleFunc({})'.format(arg))

globals()['sampleFunc']('sample arg')
0
adăugat

Răspunsul (sper) nimeni nu a vrut vreodată

Eval ca un comportament

getattr(locals().get("foo") or globals().get("foo"), "bar")()

De ce nu adăugați auto-import

getattr(
    locals().get("foo") or 
    globals().get("foo") or
    __import__("foo"), 
"bar")()

În cazul în care avem dicționare suplimentare, vrem să verificăm

getattr(next((x for x in (f("foo") for f in 
                          [locals().get, globals().get, 
                           self.__dict__.get, __import__]) 
              if x)),
"bar")()

Trebuie să mergem mai adânc

getattr(next((x for x in (f("foo") for f in 
              ([locals().get, globals().get, self.__dict__.get] +
               [d.get for d in (list(dd.values()) for dd in 
                                [locals(),globals(),self.__dict__]
                                if isinstance(dd,dict))
                if isinstance(d,dict)] + 
               [__import__])) 
        if x)),
"bar")()
0
adăugat

Incearca asta. În timp ce acesta utilizează încă eval, îl folosește doar pentru a convoca funcția din contextul curent . Apoi, aveți funcția reală de a utiliza așa cum doriți.

Principalul beneficiu pentru mine din această cauză este că veți primi orice eroare legată de eval în momentul convocării funcției. Apoi, veți primi numai erorile legate de funcție atunci când apelați.

def say_hello(name):
    print 'Hello {}!'.format(name)

# get the function by name
method_name = 'say_hello'
method = eval(method_name)

# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)
0
adăugat
Acest lucru ar fi riscant. șirul poate avea orice și evalul s-ar sfârși să o evalueze fără nici o considerație.
adăugat autor iankit
Desigur, trebuie să aveți grijă de contextul în care o utilizați, indiferent dacă aceasta este potrivită sau nu, având în vedere aceste riscuri.
adăugat autor tvt173