Skip to content

Python 类与对象

Python 支持面向对象编程(OOP):把数据与操作数据的行为封装在一起,便于复用、扩展与维护。OOP 中常见概念包括封装继承多态等;在 Python 里,类(class)对象(object,即实例) 是最基础的载体。

本篇建立整体认识;self构造函数继承等可继续阅读 self 变量类构造函数类的继承

类是什么?

是创建对象的蓝图:描述这类对象有哪些数据(属性)、有哪些行为(方法)

例如 Employee 可以有属性 employee_id、方法 work();根据同一个类可以创建多个员工对象,各自 employee_id 可以不同。

方法若需访问当前实例的数据,第一个参数习惯为 self(见 self 变量)。

定义类:class

使用关键字 class 定义类。空类可用 pass 占位:

python
class Employee:
    pass

为类添加类属性实例方法

python
class Employee:
    employee_id = 0  # 类属性(本节稍后对比「实例属性」)

    def work(self):
        print(f"{self.employee_id} is working")


emp = Employee()
print(type(emp))
emp.work()

输出:

text
<class '__main__.Employee'>
0 is working

此处实例上未单独赋值 employee_id 时,读取 self.employee_id 会找到类属性 0(所有实例默认共享该展示值,直到在实例上绑定自己的属性)。

内置函数 type(obj) 返回对象类型,可用于调试。

对象(实例)

对象是类实例化的结果。一个类可以有任意多个对象;对象可调用类上定义的方法,并拥有自己的属性命名空间。

上例中 empEmployee 的实例。实例通过 类名(...) 调用创建,背后会经历分配对象与初始化等步骤(见下文 __init__)。

默认与基类 object

在 Python 3 中,类声明若未写父类,则隐式继承内置类 object。未自定义 __init__ 时,仍会使用继承链上的默认机制完成实例创建;需要在创建后设置实例属性时,通常定义 __init__(self, ...)(常被称为初始化方法,习惯上也叫构造函数)。详见 类构造函数

使用 __init__ 设置实例属性

若希望每个员工有各自的 employee_id,应在 __init__ 里绑定到 self

python
class Employee:
    def __init__(self, i):
        self.employee_id = i

    def work(self):
        print(f"{self.employee_id} is working")


emp = Employee(100)
emp.work()

输出:

text
100 is working

此时不能再无参调用 Employee(),否则会报错:

text
TypeError: __init__() missing 1 required positional argument: 'i'

能否定义多个 __init__

Python 不像部分语言那样支持「构造函数重载」。若在类里写两个 __init__后定义的会覆盖先定义的,只保留最后一个:

python
class Employee:
    def __init__(self, id):
        self.employee_id = id

    def __init__(self, id, n):  # 覆盖上一个 __init__
        self.employee_id = id
        self.emp_name = n

    def work(self):
        print(f"{self.emp_name}[{self.employee_id}] is working")


emp = Employee(100, "Pankaj")
emp.work()

# emp = Employee(100)  # TypeError: 缺少参数 n

需要多种构造方式时,常用 @classmethod 备选构造器默认参数*args / **kwargs 等模式,而不是重复定义 __init__

类变量与实例变量

类变量实例变量
定义位置类体中、方法外通常在 __init__ 里赋给 self.xxx
共享方式被所有实例共享同一绑定(注意可变对象)每个实例各自一份
访问方式ClassName.varself.var(查找顺序有关)self.var

employee_id 若随员工变化,应作为实例变量__init__ 中设置。

下面用类变量统计创建了多少个实例,并用类变量列表记录已分配的 id。向共享列表追加时,建议显式用类名,避免读者误以为是「每个实例独有列表」:

python
class Employee:
    count = 0
    ids_list = []

    def __init__(self, i):
        self.id = i
        Employee.count += 1
        Employee.ids_list.append(i)


for x in range(10):
    Employee(x)

print(f"已创建员工数 = {Employee.count}")
print(f"已分配 id 列表 = {Employee.ids_list}")

emp = Employee(1000)
print(f"通过实例访问同一列表 = {emp.ids_list}")

输出(示意):

text
已创建员工数 = 10
已分配 id 列表 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
通过实例访问同一列表 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1000]

注意ids_list可变的类属性,所有实例看到的是同一个列表。若本意是「每个实例自己的列表」,应在 __init__ 里写 self.ids_list = [],不要与共享类变量混淆。

小结

  • 描述结构与行为;对象是类的实例。
  • __init__ 用于初始化实例属性;不要重复定义多个 __init__
  • 类变量共享、实例变量 per 实例;可变类变量要特别小心共享引用。

参考