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 Aclass 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()、魔法方法或对象比较踩过坑?欢迎在评论区分享你的经历。技术成长从来不是孤独地背诵概念,而是在一次次真实问题中,慢慢看见语言背后的设计智慧。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐