Python
中的属性操作(如获取、设置和删除属性)是我们日常编程中非常常见的操作。
但你有没有想过,当我们写下obj.attr
或obj.attr = value
时,Python
内部究竟发生了什么?
本文将探讨Python
属性的工作原理,并通过简单的代码示例来更好地理解这些概念。
1. 属性的基本操作
在Python
中,属性基本操作主要有三种:
- 获取属性值:
value = obj.attr
- 设置属性值:
obj.attr = value
- 删除属性:
del obj.attr
这些操作看似简单,但它们的实现却依赖于Python
的底层机制。
为了更好地理解这些机制,我们需要先了解描述符的概念。
2. 描述符:属性的核心机制
描述符 是Python
中一个非常重要的概念,它是实现属性功能的核心机制。
描述符 是一个对象,它通过实现特定的方法(如__get__
、__set__
和__delete__
)来控制属性的访问、设置和删除。
例如,如下实现一个简单的描述符类:
python
class Descriptor:
def __get__(self, instance, owner):
return f"从 {instance} 获取属性值"
def __set__(self, instance, value):
print(f"设置 {instance} 的属性值: {value}")
def __delete__(self, instance):
print(f"从 {instance} 中删除属性值")
我们可以将这个描述符 作为类属性使用:
python
obj = MyClass()
print(obj.attr) # 调用 __get__
obj.attr = "Hello" # 调用 __set__
del obj.attr # 调用 __delete__

在CPython
中,描述符通过tp_descr_get
和tp_descr_set
两个函数指针实现。
3. 属性的存储与查找
Python
中的属性存储在对象的字典(__dict__
)中,或者在类的字典中。
当我们访问属性时,Python
会按照以下顺序查找:
- 在实例的
__dict__
中查找 - 如果未找到,按照方法解析顺序在类及其父类的
__dict__
中查找 - 如果仍未找到,抛出
AttributeError
比如:
python
class Parent:
x = "Parent"
class Child(Parent):
y = "Child"
obj = Child()
print(obj.x) # 输出 "Parent",从父类中找到
print(obj.y) # 输出 "Child",从子类中找到
4. 类型的属性管理
类型(如int
、list
)本身也有属性,这些属性的管理方式与普通对象类似,但有一些特殊之处。
因为类型本身是一个对象,它的类型是type
,它是一个元类型。
当我们访问类型属性时,Python
会按照以下顺序查找:
- 在类型的字典中查找
- 如果未找到,按照 方法解析顺序 在元类型的字典中查找
这里有一个元类型 的概念,所谓元类型 ,是指它的实例 是一个类型。
也就是说,正如类 用于创建对象 一样,元类型 是用于创建类的。
Python
有一个内置的元类型,称为type
,它是所有内置类型中的元类型。
比如我们在Python
中创建一个类一般使用下面的方式:
python
class MyClass:
pass
也可以改成下面这样,和上面是等价的。
python
MyClass = type('MyClass', (), {})
5. 自定义属性管理
Python
允许我们通过定义特殊方法来自定义属性的行为,这些方法包括:
__getattribute__
:拦截所有属性访问__getattr__
:仅在属性未找到时被调用__setattr__
:拦截所有属性设置__delattr__
:拦截所有属性删除
下面示例中,自定义了属性的访问和设置。
python
class MyClass:
def __getattribute__(self, name):
print(f"拦截所有属性的访问: {name}")
return super().__getattribute__(name)
def __getattr__(self, name):
print(f"拦截不存在属性的访问: {name}")
return f"属性 {name} 不存在"
def __setattr__(self, name, value):
print(f"设置属性值: {name} = {value}")
super().__setattr__(name, value)
obj = MyClass()
obj.x = "Hello"
print(obj.x) # 访问存在的属性
print(obj.y) # 访问不存在的属性

当设置属性 (obj.x = "Hello"
)时,调用了 __setattr__
;
访问存在的属性 (print(obj.x)
)时,调用了__getattribute__
;
访问不存在的属性 (print(obj.y)
)时,调用了__getattribute__
和__getattr__
,
且是先调用__getattribute__
。
6. 总结
Python
的属性机制非常强大,它通过描述符、特殊方法和底层的字节码操作实现了灵活的属性管理。
通过理解这些机制,我们可以更好地设计类和对象,优化代码性能,并避免常见的陷阱。