如何调用由其名称作为字符串给出的对象的方法?

时间:2017-02-03 11:07:32

标签: python python-3.x reflection python-3.6

我有一个由

生成的python3对象(类实例)
myObj = myClass()

线。我还有一个myMethodName字符串:

myMethodName = "exampleName"

。如何调用由myObj命名的myMethodName方法?因此,在这种情况下,我想调用myObj.exampleName,它来自getAttr(myObj, myMethodName)

不幸的是,python文档引用的一个天真的解决方案(例如,here)只给我一个KeyErrorAttributeError

这失败了myObj没有method方法:

method = getAttr(myObj, myMethodName)
myObj.method(param)

失败的原因是myMethodName的参数更少:

method = getAttr(myObj, myMethodName)
method(myObj, param)

简单地打电话

method = getAttr(myObj, myMethodName)
method(param)

哪个是最符合逻辑的,给出

TypeError: exampleName() takes 1 positional argument but 2 were given

那么,我该怎么做呢?

我使用python 3.6,如果重要的话。

扩展:这是一个MCVE:

class Test:
  name = None
  def __init__(name):
    self.name = name
  def process():
    method = getattr(self, 'process_' + name)
    method("param")
  def process_test(param):
    print ("process_test(): "+param)

test = Test("cica")
test.process("test")

3 个答案:

答案 0 :(得分:2)

如果传递给getattr()的属性是方法名,那么它返回一个已绑定到该对象的可调用对象:

  

getattr(object, name[, default])

     

返回object的named属性的值。 name必须是字符串。如果字符串是其中一个object的名称   属性,结果是该属性的值。 例如,   getattr(x, 'foobar')相当于x.foobar 。如果命名   如果提供了属性,则返回default,否则返回   AttributeError被提出。

证明:

>>> x = [1, 2, 1, 3, 1, 1]
>>> f = getattr(x, 'count') # same as f = x.count
>>> f(1)
4

答案 1 :(得分:2)

您的示例可以针对以下内容进行更改:

class Test:
   def __init__(self, name):
       self.name = name
   def process(self, param):
       method = getattr(self, 'process_' + param)
       method("param")
   def process_test(self, param):
       print ("process_test(): "+param)


test = Test("cica")
test.process("test")

我认为你缺少Python中绑定/静态方法的概念。请参阅此answer,它描述了不同类型的方法。

答案 2 :(得分:1)

导致第一个错误,因为getattr返回已绑定到对象实例(myObj)的方法。

所以你要做的就是把你的method变量称为函数。

第二个错误可能是由于您的exampleName没有与传递给method的参数数量相同的参数数量。

第二个错误所需要做的就是在类中的方法中添加相同的参数:

myObj = myClass()class myClass:
    def exampleName(self, *args, **keyargs):
        print('Method exampleName was called')

myObj = myClass()

myMethodName = "exampleName"

method = getattr(myObj, myMethodName)
method('some param')

更新

您添加的示例中还有一些问题:

class Test:
    # This was removed, as you already initialize the instance variable in the constructor.
    # Setting it here would cause the variable to be shared by all instances of the class,
    # which you probably do not want, as you are passing the value as argument to the constructor below.
    # name = None

    # You missed to add the self parameter
    def __init__(self, name):
        self.name = name

    # Again, self parameter was missed
    # Additionally, we added a `suffix` parameter, that will accept the `test` value from the `process` call
    # We also added *args and **keyargs that will accept arbitrary number of parameters. Those will be
    # passed down to the `process_test` method.
    def process(self, suffix, *args, **keyargs):
        # We use the `suffix` parameter here, (instead of `name`)
        method = getattr(self, 'process_' + suffix)
        method(*args, **keyargs)

    def process_test(self, param):
        print("process_test(): " + param)


test = Test("cica")
test.process("test", "some param")