setattr() 是一个 Python 内置函数,它的全称是 "set attribute"(设置属性),它的核心功能是动态地给一个对象添加新的属性,或者修改一个对象已存在的属性。

这与我们通常使用的 object.attribute = value 的点号赋值方式效果相同,但 setattr() 提供了更灵活的动态操作能力。
语法
setattr() 的语法非常简单:
setattr(object, name, value)
参数说明:
object: 你要设置属性的目标对象,可以是一个类的实例、模块,甚至是任何其他 Python 对象。name: 你要设置的属性的名称。这是一个字符串。value: 你要赋给该属性的值,可以是任何 Python 对象(整数、字符串、列表、函数等)。
返回值:
setattr() 函数本身不返回任何值(即返回 None)。

工作原理
setattr() 的工作方式等价于以下操作:
# 这两行代码的效果是完全一样的 object.name = value # 等同于 setattr(object, 'name', value)
使用示例
示例 1:给类的实例动态添加和修改属性
这是最常见的用法。
class Person:
def __init__(self, name):
self.name = name
# 创建一个 Person 实例
p1 = Person("Alice")
# 1. 动态添加一个新属性 'age'
print("添加 'age' 属性前,p1 是否有 age 属性:", hasattr(p1, 'age')) # False
setattr(p1, 'age', 30)
print("添加 'age' 属性后,p1.age =", p1.age) # 输出: 30
# 2. 动态修改一个已存在的属性 'name'
print("修改 'name' 属性前,p1.name =", p1.name) # 输出: Alice
setattr(p1, 'name', "Bob")
print("修改 'name' 属性后,p1.name =", p1.name) # 输出: Bob
# 也可以用点号方式验证
p1.city = "New York"
print("通过点号添加 city 属性:", p1.city) # 输出: New York
示例 2:动态添加方法
setattr() 不仅可以添加数据属性,还可以添加方法(函数)。
class Dog:
def __init__(self, name):
self.name = name
my_dog = Dog("Rex")
# 定义一个函数
def bark(self):
return f"{self.name} says: Woof!"
# 将这个函数动态添加为 Dog 类的一个方法
setattr(my_dog, 'bark', bark)
# 现在可以像调用普通方法一样调用它
print(my_dog.bark()) # 输出: Rex says: Woof!
# 注意:如果添加到类上,所有实例都会拥有这个方法
Dog.bark = bark
another_dog = Dog("Buddy")
print(another_dog.bark()) # 输出: Buddy says: Woof!
示例 3:操作模块
setattr() 也可以用于操作模块,这在某些插件系统或配置加载场景中很有用。

import math # 动态给 math 模块添加一个常量 PI setattr(math, 'PI', 3.14159) # 现在就可以使用这个新属性了 print(math.PI) # 输出: 3.14159 # 也可以修改现有属性 setattr(math, 'pi', 3.14) print(math.pi) # 输出: 3.14
示例 4:与 getattr() 和 hasattr() 配合使用
setattr() 通常与 getattr()(获取属性)和 hasattr()(检查属性是否存在)一起使用,构成一个完整的动态属性操作工具集。
class Config:
DEBUG = False
HOST = "localhost"
config = Config()
# 定义一个配置项和它的值
config_settings = {
'DEBUG': True,
'PORT': 8080,
'HOST': '127.0.0.1'
}
for key, value in config_settings.items():
# 检查对象是否已有该属性
if hasattr(config, key):
print(f"更新已存在的属性: {key}")
else:
print(f"添加新属性: {key}")
# 动态设置属性
setattr(config, key, value)
# 验证结果
print(f"config.DEBUG = {config.DEBUG}") # 输出: True
print(f"config.PORT = {config.PORT}") # 输出: 8080
print(f"config.HOST = {config.HOST}") # 输出: 127.0.0.1
__setattr__ 魔法方法
需要注意的是,setattr() 函数和 __setattr__ 魔法方法是两个不同的概念,但它们紧密相关。
setattr():是一个内置函数,用于在外部代码中动态设置对象的属性。__setattr__():是一个类方法,当你在一个类中定义它时,它会拦截所有对该类实例的属性赋值操作(无论是通过obj.attr = value还是setattr(obj, 'attr', value))。
__setattr__ 的工作原理:
class MyClass:
def __init__(self, value):
# 在 __init__ 中调用 self.attr = value 也会触发 __setattr__
self.value = value
def __setattr__(self, name, value):
print(f"--- 尝试设置属性: {name} = {value} ---")
# 在这里可以添加自定义逻辑,
# 1. 记录日志
# 2. 进行类型检查
# 3. 只允许设置特定名称的属性
# 4. 对值进行加密或转换
# !!! 关键点 !!!
# 如果你在这里想给实例设置属性,必须使用 object.__setattr__
# 否则会造成无限递归,因为 self.name = value 会再次调用 __setattr__
object.__setattr__(self, name, value)
print(f"--- 属性 {name} 设置成功 ---")
# 创建实例
obj = MyClass(10)
# 输出:
# --- 尝试设置属性: value = 10 ---
# --- 属性 value 设置成功 ---
# 修改属性
obj.value = 20
# 输出:
# --- 尝试设置属性: value = 20 ---
# --- 属性 value 设置成功 ---
# 添加新属性
obj.new_attr = "hello"
# 输出:
# --- 尝试设置属性: new_attr = hello ---
# --- 属性 new_attr 设置成功 ---
总结与对比
| 特性 | setattr() |
object.__setattr__() |
|---|---|---|
| 本质 | Python 内置函数 | 类的特殊方法(魔法方法) |
| 调用者 | 外部代码 | Python 解释器(在执行赋值语句时自动调用) |
| 目的 | 动态、程序化地设置属性 | 自定义对象属性赋值的行为(拦截、验证、修改等) |
| 使用场景 | 根据变量名字符串来设置属性、配置系统、元编程等 | 实现属性访问控制、代理模式、观察者模式等高级功能 |
| 递归风险 | 无 | 有,在 __setattr__ 内部使用 self.name = value 会导致无限递归,必须使用 object.__setattr__。 |
- 当你想用代码动态地给一个对象设置属性时,使用
setattr()。 - 当你想自定义一个对象被设置属性时的行为时,在类中定义
__setattr__方法。
