2010-08-19 18 views
48

Se ho un oggetto e un nome di metodo in una stringa, come posso chiamare il metodo?Chiama un metodo Python per nome

class Foo: 
    def bar1(self): 
     print 1 
    def bar2(self): 
     print 2 

def callMethod(o, name): 
    ??? 

f = Foo() 
callMethod(f, "bar1") 
+1

Anche se sono simili, questo non è un esatto duplicato di [questa domanda] (http://stackoverflow.com/questions/3061/calling-a-function-from -a-string-with-the-functions-name-in-python), che richiede una funzione in un modulo, piuttosto che un metodo di un oggetto. – Grumdrig

risposta

73

facile:

class Foo: 
    def bar1(self): 
     print 1 
    def bar2(self): 
     print 2 

def callMethod(o, name): 
    getattr(o, name)() 


f = Foo() 
callMethod(f, "bar1") 

Date un'occhiata a getattr

È inoltre possibile utilizzare setattr per l'impostazione di classe gli attributi da nomi.

+0

Non riuscivo a trovare cosa cercare nella documentazione! Grazie! – Jazz

+0

@Jazz, è sotto build. Potrebbe essere necessario effettuare una ricerca in-page con 'C-f' – aaronasterling

+0

Prego. –

2
getattr(globals()['Foo'](), 'bar1')() 
getattr(globals()['Foo'](), 'bar2')() 

Non è necessario prima istanziare Foo!

+0

Era solo un esempio, ho una vera istanza di una vera classe! – Jazz

+2

Chiamare un metodo di una classe non inizializzata implica forse che stai facendo qualcosa di sbagliato. –

+0

cosa succede se 'pippo' non è in globali? – aaronasterling

1
def callmethod(cls, mtd_name):  
    method = getattr(cls, mtd_name) 
    method() 
4

Avevo una domanda simile, volevo chiamare il metodo di istanza per riferimento. Ecco le cose divertenti che ho trovato:

instance_of_foo=Foo() 

method_ref=getattr(Foo, 'bar') 
method_ref(instance_of_foo) # instance_of_foo becomes self 

instance_method_ref=getattr(instance_of_foo, 'bar') 
instance_method_ref() # instance_of_foo already bound into reference 

Python è incredibile!

0

Ecco una versione più generalizzata che utilizza i decoratori Python. Puoi chiamare per nome breve o lungo. L'ho trovato utile quando si implementava la CLI con comandi secondari brevi e lunghi.

I decoratori in pitone sono meravigliosi. Bruce Eckel (Pensare in Java) descrive i decoratori Python meravigliosamente qui.

http://www.artima.com/weblogs/viewpost.jsp?thread=240808 http://www.artima.com/weblogs/viewpost.jsp?thread=240845

#!/usr/bin/env python2 

from functools import wraps 


class CommandInfo(object): 
    cmds = [] 

    def __init__(self, shortname, longname, func): 
     self.shortname = shortname 
     self.longname = longname 
     self.func = func 


class CommandDispatch(object): 
    def __init__(self, shortname, longname): 
     self.shortname = shortname 
     self.longname = longname 

    def __call__(self, func): 
     print("hello from CommandDispatch's __call__") 

     @wraps(func) 
     def wrapped_func(wself, *args, **kwargs): 
      print('hello from wrapped_func, args:{0}, kwargs: {1}'.format(args, kwargs)) 
      func(wself, *args, **kwargs) 

     ci = CommandInfo 
     ci.cmds += [ci(shortname=self.shortname, longname=self.longname, func=func)] 
     return wrapped_func 

    @staticmethod 
    def func(name): 
     print('hello from CommandDispatch.func') 

     for ci in CommandInfo.cmds: 
      if ci.shortname == name or ci.longname == name: 
       return ci.func 

     raise RuntimeError('unknown command') 


@CommandDispatch(shortname='co', longname='commit') 
def commit(msg): 
    print('commit msg: {}'.format(msg)) 


commit('sample commit msg')   # Normal call by function name 

cd = CommandDispatch 
short_f = cd.func(name='co')  # Call by shortname 
short_f('short sample commit msg') 

long_f = cd.func(name='commit')  # Call by longname 
long_f('long sample commit msg') 


class A(object): 
    @CommandDispatch(shortname='Aa', longname='classAmethoda') 
    def a(self, msg): 
     print('A.a called, msg: {}'.format(msg)) 


a = A() 
short_fA = cd.func(name='Aa') 
short_fA(a, 'short A.a msg') 

long_fA = cd.func(name='classAmethoda') 
long_fA(a, 'short A.a msg') 
Problemi correlati