在 Python 中,“一切皆对象”不是一句口号,而是语言底层统一的设计原则。无论是你创建的数字、字符串,还是定义的函数、类,它们都是对象。更关键的是,连类型本身也是对象,这就形成了一个自洽的对象体系。
任何变量都是对象
尝试在一个交互式环境中查看:
x = 10
print(type(x)) # <class 'int'>
def foo():
pass
print(type(foo)) # <class 'function'>
class Bar:
pass
print(type(Bar)) # <class 'type'>
- 整数
10是对象,它的类型是int。 - 函数
foo本身也是对象,它的类型是function。 - 类
Bar同样是对象,它的类型是type。
也就是说,Python 中不存在“原始类型”的概念——在 Java 里 int 是基本类型,但在 Python 中 int 实例就是一个货真价实的对象,你可以给它添加属性(不推荐但可以做),可以检查它的 id、引用计数等所有对象共有的特征。
类型也是对象,对象必有类型
Python 对象的类型构成了一个层级关系。一切对象的终极类型源头可以追溯到两个核心元类型:type 和 object。
object是所有类的基类,任何自定义类默认继承自它(如果没指定别的父类)。type是所有类型(包括它自己)的元类。也就是说,type的类型还是type。
验证一下:
print(type(int)) # <class 'type'>
print(type(type)) # <class 'type'>
print(type(object)) # <class 'type'>
print(isinstance(int, object)) # True
print(isinstance(type, object)) # True
可以看到,int 的类型是 type(因为 int 是一种类型),而 type 的类型也是 type(它自己就是自己的类型)。同时,所有的类型都继承自 object,type 也不例外。
这个关系可以用简单的记忆图来理解:
object← 所有类的基类(包括type也是它的子类)type← 所有类型的元类(包括object的类型也是它)
实例对象 vs 类对象 vs 函数对象
实例、类、函数都是对象,但在内存中的结构和角色有细微差异:
- 实例对象:由类实例化得到,其
type指向具体的类。例如x = 10中x是int类的实例。 - 类对象:类定义本身也是一个对象,其类型是
type(或自定义的元类)。类对象可以作为属性容器(存放类变量、方法),同时也是创建实例的“工厂”。 - 函数对象:用
def定义的函数是一个function类型的对象,支持调用()操作。函数对象也是一等公民:可以赋值给变量、作为参数传递给其他函数、作为返回值。
def greet(name):
return f"Hello, {name}"
# greet 就是一个对象,我们可以操作它
f = greet # 赋值给变量
print(f("Alice")) # 调用
print(greet.__name__) # 每个函数对象都有 __name__ 等属性
这个设计到底有什么用?
理解“一切皆对象”能帮你明白很多底层行为:
- 动态类型:因为对象本身携带了类型信息,变量只是标签,同一个标签可以随时贴上不同类型的对象。
- 鸭子类型:你不用检查对象的类型是否属于某个类,只要它有你需要的方法/属性就可以用。因为本质上所有操作都是在动态查找对象身上的方法,不受静态类型体系的束缚。
- 元编程的基础:因为类也是对象,我们可以在运行时修改类、动态创建类、使用描述符和元类来控制类的行为。这在其他静态语言中需要用到复杂的反射机制,而 Python 中就是一门对象操作的延伸。
- 内存管理的一致性:所有对象都继承自
object,共享相同的引用计数和垃圾回收机制,内存管理模型极其统一。
记住一句话:在 Python 里,你写的每一行代码,操作的每一个名字,都是在跟对象打交道。哪怕是简单的赋值、函数调用、类定义,背后都是一个封装好类型、状态和行为的对象。这种一致性,是 Python 动态能力和灵活性的基石,也是理解装饰器、元类、描述符等高级特性的前置心法。