一、封装:隐藏内部实现
封装是指将对象的属性和方法 “包装” 起来,只暴露必要的接口,隐藏内部细节,Python 通过以下方式实现:
1. 私有属性 / 方法(伪私有)
Python 没有真正的私有机制,通过双下划线前缀(__属性名/__方法名)实现 “名称改写”,使其无法直接外部访问(并非绝对私有)。
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age # 私有属性(名称改写为 _Person__age)
def __secret(self): # 私有方法(名称改写为 _Person__secret)
print(f"{self.name}的年龄是{self.__age}")
# 提供公开接口访问私有属性
def get_age(self):
return self.__age
# 提供公开接口修改私有属性(可添加校验逻辑)
def set_age(self, new_age):
if 0 < new_age < 150:
self.__age = new_age
else:
raise ValueError("年龄不合法")
p = Person("王五", 20)
# print(p.__age) # 报错:AttributeError(无法直接访问)
# p.__secret() # 报错:AttributeError(无法直接调用)
# 通过公开接口访问/修改
print(p.get_age()) # 输出:20
p.set_age(21)
print(p.get_age()) # 输出:21
# 强行访问(不推荐):通过改写后的名称
print(p._Person__age) # 输出:21
2. @property 装饰器(属性访问器)
将方法转为 “属性式访问”,替代 getter/setter,让代码更简洁:
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age
# getter:将方法转为只读属性
@property
def age(self):
return self.__age
# setter:允许修改属性(需先定义 getter)
@age.setter
def age(self, new_age):
if 0 < new_age < 150:
self.__age = new_age
else:
raise ValueError("年龄不合法")
p = Person("赵六", 22)
# 访问属性(无需括号)
print(p.age) # 输出:22
# 修改属性
p.age = 23
print(p.age) # 输出:23
# p.age = 200 # 报错:ValueError
二、继承:代码复用的核心
继承允许子类(派生类)继承父类(基类 / 超类)的属性和方法,子类可扩展或重写父类逻辑。
1. 单继承
# 父类(基类)
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name}在吃东西")
# 子类(派生类):继承 Animal
class Dog(Animal):
# 重写父类方法(多态的体现)
def eat(self):
print(f"{self.name}在啃骨头")
# 新增子类方法
def bark(self):
print(f"{self.name}在汪汪叫")
dog = Dog("旺财")
dog.eat() # 输出:旺财在啃骨头(重写后的方法)
dog.bark() # 输出:旺财在汪汪叫(新增方法)
2. 多继承
Python 支持多继承(子类继承多个父类),需注意方法解析顺序(MRO) :
class A:
def show(self):
print("A")
class B:
def show(self):
print("B")
# 多继承:子类 C 继承 A、B
class C(A, B):
pass
c = C()
c.show() # 输出:A(按 MRO 顺序优先调用 A 的 show)
print(C.__mro__) # 查看 MRO:C -> A -> B -> object
3. super () 函数
用于调用父类的方法,解决多继承中的调用顺序问题:
class Parent:
def __init__(self, name):
self.name = name
print(f"Parent初始化:{self.name}")
class Child(Parent):
def __init__(self, name, age):
# 调用父类的 __init__ 方法
super().__init__(name)
self.age = age
print(f"Child初始化:{self.name},{self.age}岁")
child = Child("小明", 10)
# 输出:
# Parent初始化:小明
# Child初始化:小明,10岁
三、多态:同一接口,不同实现
多态指 “同一方法名,在不同子类中有不同实现”,调用时无需关心具体类型,只需统一接口:
class Cat(Animal):
def eat(self):
print(f"{self.name}在吃小鱼干")
# 统一接口:接收 Animal 及其子类实例
def feed_animal(animal):
animal.eat()
# 传入不同子类实例,执行不同逻辑
feed_animal(Dog("旺财")) # 输出:旺财在啃骨头
feed_animal(Cat("咪宝")) # 输出:咪宝在吃小鱼干