Menu

Python 类:__init__、self、方法、继承和 dataclass

面向初学者的 Python 类入门:定义类、创建实例、__init__ 方法、继承,以及什么时候改用 dataclass。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

类把数据和对数据的操作包装在一起

类让你定义一种事物,比如一个用户、一个银行账户、一份配置、一个请求,以及这种事物应该能做的所有事。这个“事物”就是类的“实例”。这些“操作”叫作“方法”。

下面是最简单的类:

逐项拆解:

  • class User: 开始一个类的定义。按照约定,类名使用大驼峰命名法(PascalCase)。
  • __init__ 是初始化方法。创建新实例时它会自动运行。它用 self.whatever = ... 设置实例的属性。
  • greet 是一个方法。方法通过 self 来引用调用它的那个实例。
  • User("Rosa", "rosa@example.com") 创建一个实例。Python 调用 __init__,把 self 设为这个新实例,其他参数原样传入。
  • user.greet() 调用这个方法。Python 会自动把 user 作为 self 传入。

self 只是第一个参数

self 不是关键字。它是 Python 中实例方法第一个参数的名字,也就是这个方法正在操作的实例。你“可以”给它起任何名字;大家都用 self,只因为大家都这么用。

每个实例方法都把 self 作为第一个参数。方法正是靠它知道要读取或修改哪个实例。

添加行为

方法可以读取和修改状态:

__repr__ 是另一个特殊方法,它是一个“打印时怎样显示这个对象”的钩子。定义一个好的 __repr__,调试时会让你受益匪浅。

类属性与实例属性

在类的主体中(__init__ 之外)定义的属性由所有实例“共享”。赋值给 self 的属性则是“每个实例各自独有”的:

类属性用于真正共享的值:常量、计数器、配置。实例特有的数据放在 __init__ 中。

继承

一个类可以“继承”另一个类,免费获得它的方法和属性,再按需添加或重写:

super() 让你能访问父类,常用于在 __init__ 中先初始化父类的属性,再添加自己的属性:

继承很有用,但很容易被滥用。Python 新手常常在组合(把一个对象作为属性持有)更清晰的时候选择继承。先从扁平的类结构开始,只有在真正存在“是一个”(is-a)关系时才引入继承。

Python 继承一页讲得更深入:用 super() 扩展父类方法、isinstance 和 issubclass、抽象基类、多重继承以及方法解析顺序。

dataclass:记录类数据的更好默认选择

如果你主要想让一个类保存几个属性,并具备相等比较和显示的功能,@dataclass 能帮你省掉大量样板代码:

对比一下手写 __init__、__repr__ 和 __eq__ 的工作量。如果你本来要写的 class Thing 里只有一个设置属性的 __init__,那么 dataclass 就是首选。

property:计算出来的属性

有时你想要一个实际上是计算出来的“属性”。@property 让它看起来就像访问属性一样:

在你本来会写 obj.get_something() 的地方使用 property,换成 property 会让 API 用起来更自然。不要用它来隐藏耗时的操作;使用者会认为访问属性是很快的。

约定俗成的私有

Python 没有真正的私有。按照约定,以下划线开头的属性“意在”私有,读代码的人不应该在类的外部操作它们:

class Cache:
    def __init__(self):
        self._store = {}

    def put(self, key, value):
        self._store[key] = value

    def get(self, key, default=None):
        return self._store.get(key, default)

双下划线开头的名字(__name)会触发“名称改写”(name mangling),把类名加到属性名中。这是在继承中避免命名冲突的工具,不是安全措施。

什么时候不该用类

如果你只有一组相关的数据,用 dataclass、普通字典或具名元组就可以了。如果你只有一个函数,它不需要一个类来装。当你同时有绑定在一起的状态和行为时,尤其是同一类东西会有很多实例时,再使用类。

最后一个例子

一个类似文件的小型日志缓冲区:

注意 __len__,这是另一个魔术方法。定义了它,len(logger) 就能用了,因为 len(x) 实际上是在调用 x.__len__()。Python 有几十个这样的钩子,你可以在需要时慢慢掌握。

常见问题

Python 中的类是什么?

类是创建对象的蓝图,对象把数据(属性)和行为(方法)打包在一起。class User: 定义了一个 User 类;User(...) 创建一个实例。在 Python 中,要给同时具有状态和行为的事物建模,类是主要的工具。

Python 中的 self 是什么意思?

self 是每个实例方法的第一个参数。当你调用 user.greet() 时,Python 会把 user 这个实例作为 self 传入。在方法内部,self.name 访问的就是这个用户的 name 属性。self 这个名字是约定,不是关键字,但所有 Python 程序员都这么写。

Python 是面向对象的语言吗?

是的,Python 中的一切都是对象,包括数字、字符串和函数。合适的时候你可以进行面向对象编程,但 Python 并不强制你这么做。很多实际的 Python 程序很少使用类,能用普通函数和数据结构的地方就尽量用它们。

Coddy 编程语言插图

和 Coddy 一起学编程

开始