面向对象三大特性:封装,继承,多态
一. 封装
1.1 什么是封装?
封装是面向对象编程的三大基本特性之一。封装指的是将数据和操作数据的方法绑定在一起,形成一个独立的单元(即类),并对外部隐藏对象的内部实现细节。
给属性添加保护,不让外界进行修改(通过添加get,set方法)
get方法:用来获取数据 set方法 :用来给数据赋值
核心作用:明确的区分内外,控制外部对隐藏的属性的操作行为(过滤掉异常数据)
1.2 如何设置私有属性/私有方法
1.2.1 双下划线前缀设置私有方法
python
class MyClass:
def __private_method(self):
return "这是一个私有方法"
1.2.2 双下划线前缀设置私有属性
python
class MyClass:
def __init__(self):
self.__real_private_attr = "这是一个名称修饰的私有属性" # 双下划线前缀
案例
python
class Dog:
def __init__(self,name):
self.name = name
self.__sex = '公' # 设置私有属性或方法很简单,在属性或方法前加__即可
self.__age = 1 # 给属性设置为私有属性,并且默认初始值为1
def set_age(self,age):
if age >=1 and age <=15:
self.__age = age
else:
self.__age = 1
def get_age(self):
return self.__age
def get_sex(self):
return self.__sex
def set_sex(self,sex):
if sex =='公' or sex == '母':
self.__sex = sex
else:
self.__sex = '公'
def __show(self): # 私有方法的定义方式与私有属性基本一致,在方法名的前面添加两个下划线 __方法名()
print(f"大家好,我叫{self.name},今年{self.get_age()}岁,性别为{self.get_sex()}")
def get_show(self):
return self.__show()
dg1 = Dog('旺财')
dg1.set_age(9)
dg1.set_sex('母')
# print(dg1.__sex) 外部打印不了__sex,属性被设为私有
dg1.get_show()
在这个例子中,结果会输出"大家好,我叫旺财,今年9岁,性别为母",展示私有属性,私有方法设置和简单使用。
二. 继承
2.1 什么是继承?
继承是面向对象编程中的一个核心概念,它允许新的类(子类/派生类)基于已有类(父类/基类)来创建,并自动获得父类的属性和方法。
2.2 继承的基本特点
- 代码复用:子类可以重用父类已经定义的属性和方法,避免重复编写相同代码
- 扩展性:子类可以在继承的基础上添加新的属性和方法,或修改继承来的方法实现
- 层次结构:通过继承可以建立类之间的层次关系,形成更清晰的对象模型
2.3 继承的类型
2.3.1 单继承
- 一个子类只能有一个直接父类
python
class Animal:
def eat(self):
print("Eating...")
class Dog(Animal): # Dog继承自Animal
def bark(self):
print("Barking...")
扩展特性:继承让⼦类继承⽗类的所有公共属性和⽅法,但是如果仅仅是为了继承公共 属性和⽅法,继承就没有实际的意义了 ,应该是在继承以后,⼦类应该有⼀些⾃⼰的属性和⽅法。上述代码子类重写了父类的bark方法。
什么是重写?
重写也叫作覆盖,就是当⼦类成员与⽗类成员名字相同的时候,从⽗类继承下来的成员会重新定义!
此时,通过⼦类实例化出来的对象访问相关成员的时候,真正其作⽤的是⼦类中定义的成员!
2.3.2 多级继承
python
# 多级继承:继承一个类,再继承这个类中的属性和方法
class Pet:
def __init__(self,name,age,love):
self.name = name
self.age =age
self.love = love
def show(self):
print(f"大家好,我叫{self.name},今年{self.age}岁,当前亲密度为{self.love}")
class Dog(Pet):
def __init__(self,name,age,love,type):
super().__init__(name,age,love)
self.type = type
# self.gender = gender
def show(self):
print(f"大家好,我叫{self.name},今年{self.age}岁,当前亲密度为{self.love},品种为{self.type}")
class Dog1(Dog):
def __init__(self, name,age,love,type,color):
super().__init__(name,age,love,type)
self.color = color
def show(self):
print(f"大家好,我叫{self.name},今年{self.age}岁,当前亲密度为{self.love},品种为{self.type},颜色为{self.color}")
dg1 = Dog1('旺财',5,98,'金毛','棕色')
dg1.show()
输出结果:大家好,我叫旺财,今年5岁,当前亲密度为98,品种为金毛,颜色为棕色
2.3.3 多继承
- 一个子类继承多个父类
python
class A:
def method_a(self):
print("Method A")
class B:
def method_b(self):
print("Method B")
class C(A, B): # C同时继承A和B
pass
注意:虽然多继承允许我们同时继承自多个类,但是实际开发中,应尽量避免使用多继承,因为如果两个类中出现了相同的属性和方法就会产生命名冲突。
2.3.4 案例
python
class Pet:
def __init__(self,name,age,love):
self.name = name
self.age =age
self.love = love
def show(self):
print(f"大家好,我叫{self.name},今年{self.age}岁,当前亲密度为{self.love}")
class Dog(Pet): # 父类1
def __init__(self,name,age,love,type):
super().__init__(name,age,love)
self.type = type
# self.gender = gender
def show(self):
print(f"大家好,我叫{self.name},今年{self.age}岁,当前亲密度为{self.love},品种为{self.type}")
class Insert_Dog: # 父类2
def __init__(self,fly,run):
self.fly = fly
self.run = run
class Dog2(Dog,Insert_Dog):
def __init__(self, name,age,love,type,color,fly,run):
Dog.__init__(self,name,age,love,type) # 不能使用传统的supper关键词
Insert_Dog.__init__(self,fly,run)
self.color = color
self.type = type
def show(self):
print(f"大家好,我叫{self.name},今年{self.age}岁,当前亲密度为{self.love},品种为{self.type},颜色为{self.color},我会{self.fly},还会{self.run}")
dg2 = Dog2('旺财',5,98,'金毛','棕色','飞天','奔跑')
dg2.show()
打印结果:大家好,我叫旺财,今年5岁,当前亲密度为98,品种为金毛,颜色为棕色,我会飞天,还会奔跑
三. 多态
3.1 什么是多态
定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。
不同对象 => 使用相同方法 => 产生不同的执行结果
3.2 多态的实现
多态:可以基于继承也可以不基于继承
- 多态依赖继承(不是必须的)
- 子类方法必须要重写父类方法
多态的好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化!
示例
python
# 定义一个基类 Shape(形状)
class Shape:
# 定义一个通用的绘制方法
def draw(self):
print('Drawing a shape') # 基类中的默认实现
# Circle 类继承自 Shape 类
class Circle(Shape):
# 重写父类的 draw 方法,提供圆形特有输出
def draw(self):
print('Drawing a Circle')
# Square 类继承自 Shape 类
class Square(Shape):
# 重写父类的 draw 方法,提供正方形特有的输出
def draw(self):
print('Drawing a Square')
# 定义一个多态函数,接收任意 Shape 子类对象
def draw_shape(shape):
# 调用传入对象的 draw 方法,具体执行哪个类的方法取决于传入的对象类型
shape.draw() # 这里体现了多态的核心:同一接口,不同实现
# 创建 Circle 对象实例
c1 = Circle()
# 创建 Square 对象实例
s1 = Square()
# 调用 draw_shape 函数,传入 Circle 对象
# 虽然函数参数类型是 Shape,但实际传入的是 Circle 对象
# 所以会执行 Circle 类的 draw 方法
draw_shape(c1)
输出结果:Drawing a Circle
3.3 多态的优势
-
提高代码灵活性:可以轻松添加新类型而不修改现有代码
-
增强可扩展性:系统功能容易扩展
-
提高代码复用性:相同的接口可以处理不同类型的对象
-
简化代码维护:减少条件判断语句的使用
四. 面向对象的其他属性
4.1 类属性(类的对象可以实现共享数据)
类属性就是类对象中定义的属性,它被该类的所有实例对象所共有
示例
python
class Employee:
# 类属性
company = "ABC Corporation" # 所有员工所属的公司名称
employee_count = 0 # 用于统计员工总数
def __init__(self, name):
self.name = name
Employee.employee_count += 1 # 每创建一个实例,员工总数加1
4.1.1 访问类属性
类属性可以通过类名直接访问,也可以通过类的实例访问:
python
# 通过类名访问
print(Employee.company) # 输出: ABC Corporation
# 通过实例访问
emp1 = Employee("Alice")
print(emp1.company) # 输出: ABC Corporation
4.1.2 修改类属性
要修改类属性,应该通过类名来修改,而不是通过实例:
python
Employee.company = "XYZ Corporation" # 修改类属性
print(Employee.company) # 输出: XYZ Corporation
print(emp1.company) # 输出: XYZ Corporation
4.2 类方法(作用:用于调用类属性)
类方法是面向对象编程中一种特殊的方法类型,主要用于操作类级别的属性和数据。
4.2.1 定义方式
- 使用@classmethod装饰器声明
- 第一个参数约定为cls(代表类本身)
- 可以访问类属性但不能访问实例属性
4.2.2 类方法的使用示例
python
class Employee:
raise_amount = 1.04 # 类属性
@classmethod
def set_raise_amount(cls, amount):
cls.raise_amount = amount # 修改类属性
4.3 静态方法
静态方法它属于类本身而不是类的实例。这意味着静态方法可以直接通过类名调用,而无需创建类的对象实例
python
class Student:
@staticmethod
def get_home():
print('GOOD MORNING')
print('====================放学了=================')
s1 = Student()
Student.get_home() # 直接通过类名.静态方法(逻辑归属类但不依赖类或实例的状态,提升代码可读性和复用性。)
4.4 MRO(Method Resolution Order):方法解析顺序
方法解析顺序(MRO)是Python中处理多重继承时确定方法调用顺序的重要机制。在多重继承场景下,当一个类继承自多个父类时,MRO决定了Python解释器搜索方法的顺序路径。
Python使用C3线性化算法来计算MRO顺序,该算法遵循以下三个原则:
- 子类优先于父类
- 多个父类按照声明顺序从左到右
- 保持继承图中每个类的MRO一致性
查看方法: 可以通过类的__mro__属性或mro()方法查看类的继承顺序:
python
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.__mro__) # 输出:(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
五. 总结
一、封装
核心:隐藏内部实现,提供安全访问
-
使用双下划线
__定义私有属性和方法 -
通过
getter/setter方法控制数据访问和验证 -
明确内外边界,增强代码安全性和可维护性
二、继承
核心:代码复用和扩展
-
单继承:子类拥有一个父类,实现层次化设计
-
多级继承:形成继承链,逐层扩展功能
-
多继承:一个子类继承多个父类(需注意命名冲突)
-
重写:子类重新定义父类方法,实现个性化功能
三、多态
核心:同一接口,多种实现
-
基于继承(非必需),子类重写父类方法
-
调用相同方法,根据对象类型产生不同行为
-
提高代码灵活性和可扩展性,便于编写通用程序
其他重要概念
-
类属性/方法:属于类本身,所有实例共享
-
静态方法:逻辑归属类,不依赖实例状态
-
MRO:多重继承时的方法解析顺序,确保调用路径清晰