按名称调用 Python 方法

如果在字符串中有一个对象和一个方法名称,我如何调用该方法?

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


def callMethod(o, name):
???


f = Foo()
callMethod(f, "bar1")
79441 次浏览

Use the built-in getattr() function:

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


def call_method(o, name):
return getattr(o, name)()




f = Foo()
call_method(f, "bar1")  # prints 1

You can also use setattr() for setting class attributes by names.

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

No need to instantiate Foo first!

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

I had similar question, wanted to call instance method by reference. Here are funny things I found:

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 is amazing!

Here is a more generalized version using Python decorators. You can call by short or long name. I found it useful when implementing CLI with short and long sub commands.

Python decorators are wonderful. Bruce Eckel (Thinking in Java) describes Python decorators beautifully here.

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')