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 内置语法。