Python3 面向对象

面向对象(OOP)把"数据"和"操作数据的方法"打包成类(class),再由类创建实例。 Python 一切皆对象,学会定义类、继承、魔术方法,才能写出结构清晰、可复用的代码。

类与实例:init、self 与实例方法

class 定义类,类名加括号即实例化;init 在实例化时自动执行,self 指当前实例, 实例属性挂在 self 上,实例方法第一个参数也是 self:

class Dog:
    def __init__(self, name):    # 构造方法,self 是第一个参数
        self.name = name         # 实例属性
    def bark(self):              # 实例方法,方法内用 self 访问属性
        print(f"{self.name}:汪汪!")
d = Dog("旺财")                  # 实例化
print(d.name)                    # 输出:旺财
d.bark()                         # 输出:旺财:汪汪!

类属性与实例属性

写在类体中、不带 self 的是类属性,所有实例共享;self.xxx 是实例属性,各实例独立:

class Dog:
    species = "犬科"             # 类属性
    def __init__(self, name):
        self.name = name         # 实例属性
d1, d2 = Dog("a"), Dog("b")
print(d1.species, d2.species)    # 输出:犬科 犬科
d1.species = "哺乳动物"          # 只给 d1 新建实例属性
print(d2.species, Dog.species)   # 输出:犬科 犬科

继承、super() 与方法重写

class B(A) 让 B 继承 A;super().init() 调用父类构造,复用初始化代码;子类定义 同名方法即为重写,调用时优先用子类版本:

class Animal:
    def __init__(self, name):
        self.name = name
    def sound(self):
        return "..."
class Dog(Animal):                       # 继承 Animal
    def __init__(self, name, breed):
        super().__init__(name)           # 调用父类构造方法
        self.breed = breed
    def sound(self):                     # 方法重写
        return "汪汪"
d = Dog("旺财", "金毛")
print(d.name, d.breed, d.sound())        # 输出:旺财 金毛 汪汪

多继承写作 class C(A, B),同名方法按 MRO 解析,容易混乱,建议少用。

私有属性 _x 与 __x

_x 表示"内部使用"(软私有);__x 会被名称改写为 _类名__x,类外难以直接访问:

class Account:
    def __init__(self):
        self._inner = 1     # 约定私有
        self.__secret = 2   # 名称改写为 _Account__secret
a = Account()
print(a._inner)             # 输出:1(仍可访问)
# print(a.__secret)         # 会报 AttributeError
print(a._Account__secret)   # 输出:2(实际存储名)

常用魔术方法

str/repr/len/eq 等双下划线方法会被自动调用:

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y
    def __str__(self):        # print() 时调用,给人看
        return f"({self.x}, {self.y})"
    def __repr__(self):       # 交互模式显示,更精确
        return f"Point({self.x}, {self.y})"
    def __len__(self):        # len() 时调用
        return 2
    def __eq__(self, other):  # == 比较时调用
        return self.x == other.x and self.y == other.y
p1, p2 = Point(1, 2), Point(1, 2)
print(p1)                     # 输出:(1, 2)      __str__
print(len(p1))                # 输出:2           __len__
print(p1 == p2)               # 输出:True        __eq__

小结:class 定义类、实例化执行 init 并以 self 挂属性;class B(A) 继承并配 super() 复用父类,子类可重写方法;_x/__x 控制私有,魔术方法融入 Python 内置语法。

笔记加载中…