从 getattr() 访问对象方法

Access object methods from getattr()

我需要创建一个脚本,允许您从 getattr() 内置函数动态访问对象属性,但是在尝试访问对象方法时我遇到了很多麻烦,这里是一个示例:

class Dog():
    def __init__(self):
        self.age = 12
        self.name = 'Bobby'
    
    def eat(self):
        print("I'm eating!")

如果我随后初始化对象并尝试访问它们的属性:

mydog = Dog()

res = getattr(mydog, 'age')
print(res)
#--> return: 12

但是如果我尝试访问 eat 方法:

mydog = Dog()

res = getattr(mydog, 'eat()')
print(res)
#--> return: AttributeError: 'Dog' object has no attribute 'eat()'

我已经尝试过写不带引号的方法名,我找到的最好的解决办法是写不带括号的方法,然后从 res:

访问函数
mydog = Dog()

res = getattr(mydog, 'eat')
res()
#--> return: I'm eating!

我可以编写一个条件语句来检测 res 是否包含变量或函数并调用它以防它是一个方法,但是有更好的解决方案吗?

使用一个小的单行条件来为你检测它是不错的,而且使用 callable:

很短
attr = getattr(mydog, attr_name)
res = attr() if callable(attr) else attr

在Python3.8,你甚至可以一行:

res = attr() if callable(attr := getattr(mydog, attr_name)) else attr

在方法 eat 上使用 @property 装饰器,它将成功,这样我们就可以毫无问题地检索它 getattr:

class Dog():
    def __init__(self):
        self.age = 12
        self.name = 'Bobby'

    @property
    def eat(self):
        return "I'm eating!"

mydog = Dog()
res1 = getattr(mydog, 'age')
res2 = getattr(mydog, 'name')
res3 = getattr(mydog, 'eat')
print(res1) #Output: 12
print(res2) #Output: Bobby
print(res3) #Output: I'm eating!

如果我们不将 eat 变成 属性,那么调用 getattr(mydog, "eat") 将 return 引用该方法而不调用它。但是,当您在方法中设置 @property 时,将创建 eatgetter,当您尝试调用该属性时将调用它。

如果我们想扩展上面的内容,以便我们可以更改 eat 的值,那么我们还可以创建一个 setter 的 eat:

class Dog():
    def __init__(self):
        self._eat = "I'm eating!"

    @property
    def eat(self):
        return self._eat
    
    @eat.setter
    def eat(self, eat_string):
        self._eat = eat_string

mydog = Dog()
print(mydog.eat) #Output: I'm eating!
mydog.eat = "Stop bothering me!"
print(mydog.eat) #Output: Stop bothering me!