Python getattr() 函数

Python getattr() 语法

getattr() 是 Python 的一个内置函数,它用于获取对象某个属性的值。

getattr() 是 object.name 访问形式的动态版本。在需要根据变量名动态访问属性,或者处理可能存在或不存在的属性时,getattr() 非常有用。

语法:

getattr(object, name, default=None)

说明:

getattr() 函数接收以下 3 个参数。

  • object(必选):是一个对象,包括类、对象(实例)、模块等。
  • name(必选):是一个属性名或方法名,它是一个字符串(区分大小写)。
  • default(可选,默认值:None):属性不存在时返回的值。如果提供了这个参数,即使属性不存在,getattr() 也不会引发 AttributeError。

对于 getattr() 的返回值,需要分以下情况:

  • 如果 object 具有名为 name 的属性,则返回该属性的值。
  • 如果 object 没有名为 name 的属性,并且提供了 default 参数,则返回 default 的值。
  • 如果 object 没有名为 name 的属性,并且未提供 default 参数,则引发 AttributeError。

提示: 我们可以先用 hasattr() 检查属性是否存在,再用 getattr() 获取值,但这通常不如直接使用带 default 参数的 getattr() 简洁。

Python getattr() 摘要

使用频率
官方文档 查看
相关函数 hasattr()setattr()delattr()

Python getattr() 示例

接下来,我们通过几个简单的例子来讲解一下 Python getattr() 函数是如何使用的。

示例 1:getattr() 基本用法

class Hero:
    name = '船长'
    type = '力量型'
h = Hero()

print(h.name)
print(getattr(h, 'name'))

运行结果如下。

船长
船长

分析:

从上面可以看出,如果想要获取对象某个属性的值,有以下两种方式:

# 方式 1:使用点运算符
对象名.属性名

# 方式 2:使用 getattr() 函数
getattr(对象名, 属性名)

示例 2:getattr() 找不到属性

class Hero:
    name = '船长'
    type = '力量型'
h = Hero()

print(getattr(h, 'skin'))

运行结果如下。

(报错)AttributeError: 'Hero' object has no attribute 'skin'

分析:

当 getattr() 找不到属性时,会抛出一个 AttributeError 异常。我们也可以给 getattr() 函数添加一个默认返回值,比如:

print(getattr(h, 'skin', 'red'))

示例 3:getattr() 执行动态方法

class Player:
    def attack(self):
        return '攻击!'
    def defend(self):
        return '防御!'

p = Player()
action = input('输入动作(attack/defend): ')
method = getattr(p, action, lambda: '无效指令')
print(method())

运行之后,当我们输入 “attack”,此时输出结果如下:

攻击!

分析:

在上面例子中,我们通过使用 getattr() 函数,来根据用户输入的动作(attack 或 defend)来动态调用相应的方法。如果输入无效,则执行默认的匿名函数,返回 '无效指令'。

示例 4:getattr() 获取模块属性

import math

sqrt_func = getattr(math, 'sqrt', None)
if sqrt_func:
    print(sqrt_func(9))
else:
    print('sqrt函数不存在')

运行结果如下。

3.0

分析:

getattr() 函数同样可以获取模块的属性(即函数)。

深入理解 getattr()

getattr() 函数不仅仅是获取属性的工具,它还在高级编程场景中扮演着关键角色,帮助我们编写更灵活、更高效的代码。

1. 动态接口与插件系统

在构建动态接口或插件系统时,getattr() 函数能实现按需加载功能。想象一下,你的应用程序允许用户安装不同的插件,每个插件可能实现了一些特定的操作。你不需要提前知道所有插件会提供哪些方法,而可以在运行时动态地去查找和调用。

通过将方法名作为字符串参数传递给 getattr(),你可以动态获取插件对象中的方法。接着,结合 callable() 函数检查这个方法是否真的可以被调用。如果方法存在且可调用,就执行它;否则,你可以选择抛出异常或进行其他处理。

def execute_plugin(plugin, method_name):
    func = getattr(plugin, method_name, None)
    if callable(func):
        return func()
    else:
        raise ValueError(f'插件未实现方法:{method_name}')

2. 延迟加载优化性能

getattr() 与 @property 结合使用,可以实现延迟加载来优化性能。例如,在需要处理大量数据时,可以通过 @property 定义一个属性,在首次访问时加载数据,而不是在初始化时就加载。

getattr() 可以触发这种延迟加载机制,确保资源仅在需要时才被加载。这种方式特别适用于处理大数据或高开销资源的场景,能够显著减少初始化时间和内存占用,提升程序的运行效率。

class HeavyData:
    def __init__(self):
        self._data = None
    
    @property
    def data(self):
        if self._data is None:
            print('加载大数据...')
            self._data = [i**2 for i in range(10**6)]
        return self._data

hd = HeavyData()
print(getattr(hd, 'data')[:3])      # 首次访问触发加载,输出:[0, 1, 4]

常见问题

1. 如何安全地获取可能不存在的属性?

我们可以优先使用 default 参数,比如:

value = getattr(obj, 'x', '默认值')

2. 通过 getattr() 能否获取私有属性?

我们需要使用名称修饰后的名称(如 _ClassName__var):

class Secure:
    def __init__(self):
        self.__key = 'secret'

s = Secure()
print(getattr(s, '_Secure__key'))    # 输出:secret

3. getattr() 与 “.” 运算符的性能差异?

“.” 运算符直接访问属性,速度更快。而 getattr() 更适合动态场景,但略有性能损耗。

上一篇: hasattr()

下一篇: setattr()

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号