2013-09-13 4 views
1

Мне нужно динамически вызывать метод для класса, который принимает различные параметры на основе имени строки и словаря переменных. Я знаю, как найти подпись с модулем проверки, и я могу получить метод с getattr, но я не знаю, как назначить параметры в правильном порядке, чтобы вызывать его чисто динамическим способом.Python3: динамический вызов метода со словарем параметров

class MyClass(): 
    def call_me(a, b, *args, foo='bar', **kwargs): 
     print('Hey, I got called!') 

command = { 
      'action':'call_me', 
      'parameters':{ 
         'a': 'Apple', 
         'b': 'Banana', 
         'args':['one','two','three','four'], 
         'foo':'spam', 
         'clowns':'bad', 
         'chickens':'good' 
         } 
      } 

me = MyClass() 
action = getattr(me,command['action']) 

... now what? 

Мне нужно, чтобы иметь возможность динамически вызывать эту функцию, как если бы использовал этот код, без какого-либо предвидения фактических параметров методы:

a = command['parameters']['a'] 
b = command['parameters']['b'] 
args = command['parameters']['args'] 
foo = command['parameters']['foo'] 
kwargs = { 
      'clowns': command['parameters']['clowns'], 
      'chickens':command['parameters']['chickens'] 
     } 

value = action(a, b, *args, foo=foo, **kwargs) 

Конечно есть хороший вещий способ сделай это.

Редактировать: Исправлено getattr для вызова экземпляра MyClass вместо MyClass напрямую.

+2

'action (** command ['parameters'])' – falsetru

+1

@falsetru Это не так просто из-за '* args'. – flornquake

+0

'args = command ['parameters']. Pop ('args', None); action (** команда ['parameters'], * args) ' – refi64

ответ

0

Это самый лучший способ, который я нашел до сих пор, чтобы захватить все возможные комбинации нормальных арг, * арг, ключевое слово арг и ** kwargs без получения каких-либо ошибок:

import inspect 
class MyClass(): 
    def a(self): 
     pass 
    def b(self,foo): 
     pass 
    def c(self,foo,*extras): 
     pass 
    def d(self,foo,food='spam'): 
     pass 
    def e(self,foo,**kwargs): 
     pass 
    def f(self,foo,*extras,food='spam'): 
     pass 
    def g(self,foo,*extras,**kwargs): 
     pass 
    def h(self,foo,*extras,food='spam',**kwargs): 
     pass 
    def i(self,*extras): 
     pass 
    def j(self,*extras,food='spam'): 
     pass 
    def k(self,*extras,**kwargs): 
     pass 
    def l(self,*extras,food='spam',**kwargs): 
     pass 
    def m(self,food='spam'): 
     pass 
    def n(self,food='spam',**kwargs): 
     pass 
    def o(self,**kwargs): 
     pass 


def dynamic_invoke(obj,name,parameters): 
    action = getattr(obj,name) 
    spec = inspect.getfullargspec(action) 

    used = [] 
    args =() 
    kwargs = {} 

    for a in spec.args[1:]: 
     # skip the "self" argument since we are bound to a class 
     args += (parameters[a],) 
     used.append(a) 

    if spec.varargs: 
     args += tuple(parameters[spec.varargs]) 
     used.append(spec.varargs) 

    for kw in spec.kwonlyargs: 
     try: 
      kwargs[kw] = parameters[kw] 
      used.append(kw) 
     except KeyError: 
      pass 

    # pass remaining parameters to kwargs, if allowed 
    if spec.varkw: 
     for k,v in parameters.items(): 
      if k not in used: 
       kwargs[k] = v 

    return action(*args,**kwargs) 

me = MyClass() 
params = { 
     'foo':'bar', 
     'extras':['one','two','three','four'], 
     'food':'eggs', 
     'parrot':'blue' 
     } 

dynamic_invoke(me,'a',params) 
dynamic_invoke(me,'b',params) 
dynamic_invoke(me,'c',params) 
dynamic_invoke(me,'d',params) 
dynamic_invoke(me,'e',params) 
dynamic_invoke(me,'f',params) 
dynamic_invoke(me,'g',params) 
dynamic_invoke(me,'h',params) 
dynamic_invoke(me,'i',params) 
dynamic_invoke(me,'j',params) 
dynamic_invoke(me,'k',params) 
dynamic_invoke(me,'l',params) 
dynamic_invoke(me,'m',params) 
dynamic_invoke(me,'n',params) 
dynamic_invoke(me,'o',params) 
print('done!') 
0

Try так:

action = getattr(me,command['action']) 
action(**{'a': 'Apple', 
     'b': 'Banana', 
     'args':['one','two','three','four'], 
     'foo':'spam', 
     'clowns':'bad', 
     'chickens':'good' 
    }) 
Смежные вопросы