python--面向对象(2)

43 阅读3分钟

一、封装:隐藏内部实现

封装是指将对象的属性和方法 “包装” 起来,只暴露必要的接口,隐藏内部细节,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("咪宝"))  # 输出:咪宝在吃小鱼干