Python 中的 `object` 类扮演什么角色?从万物皆对象到面向对象底层机制
Python 中的 object 类扮演什么角色?从万物皆对象到面向对象底层机制
在学习 Python 的过程中,很多人都会听到一句话:Python 中万物皆对象。数字是对象,字符串是对象,函数是对象,类本身也是对象。可当我们真正写代码时,却很少主动使用 object 这个类。它似乎一直存在,却又很少被提起。
那么,object 到底是什么?它只是一个“祖先类”吗?它为什么出现在所有类的继承链末端?理解它,对我们写出更优雅、更健壮、更符合 Python 思维的代码有什么帮助?
这篇文章将从基础到进阶,系统讲清楚 Python 中 object 类的核心角色,并通过代码示例、实践案例和常见误区,帮助你真正理解 Python 面向对象体系的根基。
一、从一句话开始:Python 中一切类都继承自 object
在 Python 3 中,所有类默认都继承自 object。也就是说,下面两种写法在本质上是等价的:
class User:
pass
class Product(object):
pass
在 Python 3 里,即使你没有显式写出 (object),Python 也会自动让 User 继承自 object。
我们可以验证一下:
class User:
pass
print(User.__mro__)
输出结果类似:
(<class '__main__.User'>, <class 'object'>)
这里的 __mro__ 表示 Method Resolution Order,也就是方法解析顺序。它告诉我们:当访问 User 实例的方法或属性时,Python 会先在 User 中查找,如果找不到,就继续到 object 中查找。
这意味着:object 是 Python 新式类体系中所有类的共同祖先。
二、object 的第一个角色:统一 Python 的对象模型
Python 的美感之一,是它用非常统一的方式看待世界。
print(isinstance(1, object))
print(isinstance("hello", object))
print(isinstance([], object))
print(isinstance({}, object))
print(isinstance(lambda x: x + 1, object))
print(isinstance(type, object))
这些结果都是:
True
整数、字符串、列表、字典、函数、类,都是对象。它们虽然表现不同,但都处在同一套对象系统之中。
这就是 object 的第一个重要作用:它统一了 Python 的对象世界,让所有类型都可以在同一套规则下运行。
这也是为什么 Python 可以轻松实现许多灵活特性,例如:
def call_twice(func, value):
return func(func(value))
print(call_twice(lambda x: x * 2, 10))
函数可以作为参数传递,是因为函数也是对象。类可以动态创建,也是因为类本身也是对象。Python 的灵活性并不是魔法,而是来自统一的对象模型,而 object 正是这个模型的根。
三、object 的第二个角色:提供所有对象的基础行为
即使你写了一个空类,它的实例也不是“什么都没有”。
class Empty:
pass
e = Empty()
print(e)
print(type(e))
print(dir(e))
你会发现,e 拥有很多看起来“自动出现”的方法,例如:
__class__
__delattr__
__dir__
__eq__
__format__
__ge__
__getattribute__
__hash__
__init__
__init_subclass__
__le__
__lt__
__ne__
__new__
__reduce__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
这些方法大多来自 object。它们构成了 Python 对象的基础行为。
例如,为什么任何对象都能被 print()?
class User:
pass
u = User()
print(u)
输出类似:
<__main__.User object at 0x...>
这是因为 object 提供了默认的 __repr__ 和 __str__ 行为。
我们可以通过重写它,让对象输出更友好:
class User:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"User(name={self.name!r})"
u = User("Alice")
print(u)
输出:
User(name='Alice')
再比如,对象为什么可以比较是否相等?
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2)
默认结果是:
False
因为 object.__eq__ 默认比较的是对象身份,而不是对象内容。要比较内容,需要自己定义规则:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2)
输出:
True
从这里可以看到,object 提供了默认行为,而我们可以通过重写特殊方法,让对象拥有符合业务语义的表现。
四、object 的第三个角色:站在继承链的终点
在面向对象编程中,继承链不可能无限向上。Python 中所有普通类的继承链最终都会抵达 object。
可以用一个简单示意图表示:
object
↑
Animal
↑
Dog
对应代码:
class Animal:
def speak(self):
return "some sound"
class Dog(Animal):
def speak(self):
return "wang wang"
dog = Dog()
print(Dog.__mro__)
print(dog.speak())
输出类似:
(<class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>)
wang wang
当我们调用 dog.speak() 时,Python 按照 MRO 顺序查找方法:
Dog -> Animal -> object
如果 Dog 中找到了 speak,就直接调用;如果找不到,就去 Animal;再找不到,就到 object。
这个机制在多继承中尤其重要。
class A:
def run(self):
print("A.run")
class B(A):
pass
class C(A):
def run(self):
print("C.run")
class D(B, C):
pass
print(D.__mro__)
d = D()
d.run()
输出类似:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
C.run
object 位于继承链的最后,它像一块地基,承托起整个类体系。理解 __mro__,你就能更从容地处理继承、混入类、框架基类和复杂业务模型。
五、object 的第四个角色:参与对象创建流程
创建一个对象时,很多初学者以为只发生了 __init__。实际上,对象创建通常包括两个阶段:
__new__ 创建对象
__init__ 初始化对象
__new__ 是真正创建实例的方法,而 __init__ 是在实例创建完成后进行初始化。
class User:
def __new__(cls, *args, **kwargs):
print("__new__ called")
instance = super().__new__(cls)
return instance
def __init__(self, name):
print("__init__ called")
self.name = name
u = User("Alice")
print(u.name)
输出:
__new__ called
__init__ called
Alice
这里的 super().__new__(cls) 最终会调用到 object.__new__。这说明 object 不仅是继承链上的终点,也参与了对象创建的底层流程。
这个机制在实现不可变对象、单例模式、ORM 模型、序列化框架时非常重要。
例如,一个简单的单例模式:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
a = Singleton()
b = Singleton()
print(a is b)
输出:
True
不过在真实项目中,单例模式要谨慎使用,因为它可能隐藏状态、降低测试性。更推荐使用依赖注入或显式配置管理。
六、object 的第五个角色:让 super() 能够协作运行
很多开发者知道 super() 可以调用父类方法,但不知道它依赖 MRO 协作。object 是这个协作链条的终点。
看一个例子:
class Base:
def __init__(self):
print("Base init")
super().__init__()
class LoggerMixin:
def __init__(self):
print("LoggerMixin init")
super().__init__()
class Service(LoggerMixin, Base):
def __init__(self):
print("Service init")
super().__init__()
s = Service()
print(Service.__mro__)
输出类似:
Service init
LoggerMixin init
Base init
(<class '__main__.Service'>, <class '__main__.LoggerMixin'>, <class '__main__.Base'>, <class 'object'>)
当所有类都正确调用 super() 时,初始化流程会沿着 MRO 顺序平稳运行,最后到达 object.__init__。
这在框架代码中非常常见。例如 Django、Flask 扩展、FastAPI 依赖注入、数据模型库等,都大量依赖继承、混入类和协作式初始化。
最佳实践是:如果你的类可能被继承,尤其是在多继承场景中,尽量使用协作式写法。
class Base:
def __init__(self, **kwargs):
super().__init__()
class Named:
def __init__(self, name, **kwargs):
self.name = name
super().__init__(**kwargs)
class Timestamped:
def __init__(self, created_at, **kwargs):
self.created_at = created_at
super().__init__(**kwargs)
class Document(Named, Timestamped, Base):
def __init__(self, name, created_at):
super().__init__(name=name, created_at=created_at)
doc = Document("report.pdf", "2026-06-04")
print(doc.name)
print(doc.created_at)
这种写法让多个父类能够优雅协作,而不是互相覆盖。
七、进阶理解:object 与属性访问机制
Python 对象访问属性时,并不是简单地“从字典里拿值”。背后会涉及 __getattribute__、__getattr__、描述符、实例字典和类字典等机制。
其中,object.__getattribute__ 是所有属性访问的基础入口。
class User:
def __init__(self, name):
self.name = name
def __getattribute__(self, item):
print(f"正在访问属性:{item}")
return super().__getattribute__(item)
u = User("Alice")
print(u.name)
输出:
正在访问属性:name
Alice
这类能力非常强大,但也很危险。因为只要写错,就可能导致无限递归。
错误示例:
class Bad:
def __getattribute__(self, item):
return self.__dict__[item]
这里访问 self.__dict__ 又会触发 __getattribute__,从而导致递归错误。
正确做法是调用父类实现:
class Safe:
def __getattribute__(self, item):
print(f"access {item}")
return object.__getattribute__(self, item)
在实际项目中,除非你在写 ORM、配置系统、代理对象、懒加载对象或调试工具,否则不建议随意重写 __getattribute__。大多数业务代码用 @property 就足够了。
class Account:
def __init__(self, balance):
self._balance = balance
@property
def balance(self):
if self._balance < 0:
raise ValueError("余额异常")
return self._balance
account = Account(100)
print(account.balance)
八、实践案例:用 object 思维设计一个可扩展插件系统
理解 object 的价值,不只是为了回答面试题,更是为了写出可扩展的业务代码。
假设我们要设计一个数据处理系统,支持不同格式的数据导出:CSV、JSON、XML。我们可以定义一个基础类,让所有插件遵循统一协议。
class Exporter:
def export(self, data):
raise NotImplementedError("子类必须实现 export 方法")
class CSVExporter(Exporter):
def export(self, data):
return "\n".join(",".join(map(str, row)) for row in data)
class JSONExporter(Exporter):
def export(self, data):
import json
return json.dumps(data, ensure_ascii=False)
def run_export(exporter: Exporter, data):
return exporter.export(data)
data = [
["name", "score"],
["Alice", 95],
["Bob", 88],
]
print(run_export(CSVExporter(), data))
print(run_export(JSONExporter(), data))
这个设计背后的思想是:
object
↑
Exporter
↑
CSVExporter / JSONExporter
我们用继承建立共性,用多态隐藏差异,用统一接口提升扩展性。
进一步,我们可以利用 __init_subclass__ 自动注册插件。这个方法也是由 object 提供的类创建钩子之一。
class Exporter:
registry = {}
def __init_subclass__(cls, name=None, **kwargs):
super().__init_subclass__(**kwargs)
if name:
cls.registry[name] = cls
def export(self, data):
raise NotImplementedError
class CSVExporter(Exporter, name="csv"):
def export(self, data):
return "\n".join(",".join(map(str, row)) for row in data)
class JSONExporter(Exporter, name="json"):
def export(self, data):
import json
return json.dumps(data, ensure_ascii=False)
def create_exporter(format_name):
exporter_cls = Exporter.registry[format_name]
return exporter_cls()
exporter = create_exporter("json")
print(exporter.export({"name": "Alice", "score": 95}))
这个案例看似简单,却包含了 Python 面向对象的核心能力:继承、多态、类钩子、动态注册和接口抽象。理解 object,就能更自然地掌握这些高级技巧。
九、常见误区:object 不是“没用的父类”
误区一:class A 和 class A(object) 完全没区别,所以 object 没意义
在 Python 3 中,这两种写法确实基本等价。但这不代表 object 没意义,而是因为 Python 已经默认帮你继承了它。
object 的意义不在于你是否显式写出来,而在于它始终存在于类体系底部。
误区二:object 只是继承链终点
它不只是终点,还提供默认方法、对象创建机制、属性访问机制、类创建钩子和基础协议。
误区三:高级魔法方法越多越好
并不是。重写 __new__、__getattribute__、__setattr__ 等方法时要非常谨慎。它们很强大,但容易让代码变得难以调试。
在工程实践中,优先选择简单、清晰、可测试的方案。
十、最佳实践:如何在项目中正确理解和使用 object
第一,学习 __mro__。当你使用继承、多继承或 mixin 时,先打印 MRO,理解方法查找路径。
print(MyClass.__mro__)
第二,重写特殊方法要服务于业务语义。比如 __repr__ 应该帮助调试,__eq__ 应该表达对象相等的业务规则,__hash__ 要与 __eq__ 保持一致。
class User:
def __init__(self, user_id):
self.user_id = user_id
def __eq__(self, other):
return isinstance(other, User) and self.user_id == other.user_id
def __hash__(self):
return hash(self.user_id)
第三,多继承中坚持使用 super(),并让参数设计更兼容。
class Mixin:
def __init__(self, **kwargs):
super().__init__(**kwargs)
第四,不要为了“炫技”滥用元编程。object 提供了强大的底层能力,但优秀的 Python 代码不是魔法越多越好,而是让读者一眼能看懂意图。
第五,多使用标准工具减少样板代码。例如数据类:
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
u = User("Alice", 18)
print(u)
输出:
User(name='Alice', age=18)
dataclass 自动生成了初始化、表示、比较等方法,本质上也是在对象模型之上做工程化封装。
十一、面试与实战中如何回答这个问题
如果在面试中被问到“Python 中的 object 类扮演什么角色?”,可以这样回答:
object 是 Python 3 中所有类的根基类。它统一了 Python 的对象模型,使数字、字符串、函数、类、实例都能被视为对象。它为所有对象提供基础行为,例如对象创建、字符串表示、比较、哈希、属性访问和类创建钩子。所有普通类的 MRO 最终都会到达 object,因此它也是方法解析链的终点。理解 object 有助于掌握继承、多态、super、多继承、魔法方法、元编程和框架设计。
这个回答既有理论,也能体现你对 Python 底层机制和工程实践的理解。
十二、总结:理解 object,就是理解 Python 的地基
object 很少被我们直接调用,却无处不在。它像建筑里的地基,平时不会被看见,但一旦缺少它,整个对象系统就无法站稳。
对初学者来说,理解 object 可以帮助你明白为什么 Python 说“万物皆对象”,为什么空类也拥有很多默认方法,为什么类可以继承、重写和多态。
对进阶开发者来说,理解 object 可以帮助你更好地掌握 MRO、super()、__new__、__getattribute__、__init_subclass__ 等底层机制,从而更从容地阅读框架源码,设计可扩展系统,写出更优雅的 Python 代码。
Python 编程的魅力,不只在于语法简洁,更在于它用一套统一而灵活的对象模型,把复杂世界组织得清晰、有序、可组合。object 正是这套模型的起点,也是每一个 Python 开发者值得认真理解的基础。
你在日常 Python 实战中,有没有因为继承、super()、魔法方法或对象比较踩过坑?欢迎在评论区分享你的经历。技术成长从来不是孤独地背诵概念,而是在一次次真实问题中,慢慢看见语言背后的设计智慧。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)