一、封装
封装是一种将数据和相关方法组合成一个单独的实体的机制。它将数据(属性)和操作数据的方法(方法)封装在一个对象中,并对外部代码隐藏了内部的实现细节。通过封装,对象可以提供一个公共接口,使得外部代码可以通过该接口访问和操作对象的数据,而不
需要了解其内部的具体实现。
封装之后:可以使用对象.属性的方法,不需要记所有的方法和属性。 掩藏属性
二、继承
继承是新建类的一种方式,新建出来的类称作子类,被继承的类叫父类
它允许新类(子类)继承现有类(父类)的属性和方法,并且可以在新类中添加新的属性和方法,或者重写父类的方法来定制子类的行为。
继承促进了代码的重用和扩展(),并且提供了层次化和组织化的代码结构。解决了类与类之间的代码冗余问题
1、为什么要继承?
类解决什么问题:解决的是对象与对象之间的代码冗余问题
继承解决什么问题:解决的是类与类之间的代码冗余问题
2、子类的继承可以有多个父类
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Parent1( object ):
pass
class Parent2:
pass
# 子类
class Sub1(Parent1):
pass
# 多继承, 括号里面可以写多个类
class Sub2(Parent1, Parent2):
pass
|
3、查看一个类继承了哪些父类,.__bases__方法
1 2 3 |
print (Sub1.__bases__) # (<class '__main__.Parent1'>,)
print (Sub2.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
print (Parent1.__bases__) # (<class 'object'>,)
|
注:python3中新定义的父类默认继承的是object类,所以父类也是一个子类
4、继承小案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class People: # 定义一个父类
school = 'SH' # 严格依赖继承
def __init__( self , name, age, gender):
self .name = name
self .age = age
self .gender = gender
class Student(People):
def __init__( self , name, age, gender, course):
"""这个是指名道姓的调用方法,不依赖于继承"""
People.__init__( self , name, age, gender) # name, age, gender 继承父类的属性
self .course = course
# 选课
def choose_course( self ):
pass
class teacher(People):
def __init__( self , name, age, gender, level):
People.__init__( self , name, age, gender)
self .level = level # 教室职称
stu = Student( 'kevin' , '19' , 'male' , 'python' )
teacher1 = teacher( '王刚' , 40 , 'male' , '高级教师' )
print (stu.name) # kevin
print (teacher1.level) # 高级教师
|
5、单继承下的属性查找
先从对象自己的名称空间中查找,然后去产生这个对象的类中查找,最后在去继承的父类中查找
6、多继承下的属性查找
多继承下的属性查找分为:菱形查找和非菱形查找
菱形查找分:经典类和新式类
经典类:按照深度优先查询
新式类:按照的广度优先查询
非菱形查找
注:在python3 中都是新式类
所以,多继承下的属性查找,如果属性找不到,就按照广度优先查询
菱形查找:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
class G( object ):
def test( self ):
print ( 'from G' )
class E(G):
def test( self ):
print ( 'from E' )
class F(G):
def test( self ):
print ( 'from F' )
class B(E):
def test( self ):
print ( 'from B' )
class C(F):
def test( self ):
print ( 'from C' )
class D(G):
def test( self ):
print ( 'from D' )
class A(B,C,D):
# def test(self):
# print('from A')
pass
obj = A()
obj.test() # 如上图,查找顺序为:obj->A->B->E->C->F->D->G->object
# 可依次注释上述类中的方法test来进行验证
|
⚠️:
1. 广度优先查找:从B开始到E回头,C到F,即查找到根部的上一级,最后一个分支查找到根部G
2. 如果D分支没有继承G,会在F查找完后查找G,形成菱形查找
7、super()内置函数与mro列表
super()
是一个内置函数,用于调用父类的方法。它提供了一种方便的方式来访问父类的属性和方法,从而实现方法重写和继承(派生)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class ParentClass:
def __init__( self ):
self .parent_attr = "I am the parent class"
def some_method( self ):
print ( "This is the parent class method" )
class ChildClass(ParentClass):
def __init__( self ):
super (ParentClass, self ).__init__() # python2 的写法,python3 兼容调构造方法
self .child_attr = "I am the child class"
def some_method( self ):
super ().some_method() # python2 的写法不支持
print ( "This is the child class method" )
# 创建子类对象
child = ChildClass()
# 访问子类和父类的属性
# print(child.child_attr) # 输出: I am the child class
# print(child.parent_attr) # 输出: I am the parent class
# 调用子类和父类的方法
child.some_method()
# 输出:
# This is the parent class method
# This is the child class method
|
如果不用super()方法来实现派生与方法重用:
指名道姓的调用某一个类的函数(不依赖于继承)
派生:比父类多的功能,派生方法。
相同的方法:重写
1 2 3 4 5 6 7 8 |
class ChildClass(ParentClass):
def __init__( self ):
ParentClass.__init__( self )
self .child_attr = "I am the child class"
def some_method( self ):
ParentClass.some_method( self )
print ( "This is the child class method" )
|
mro列表
mro
(Method Resolution Order)是指在多重继承中确定方法调用顺序的算法。Python中的每个类都有一个mro列表,它决定了方法解析的顺序。MRO列表可以通过
__mro__
属性来访问,它是一个元组,按照方法解析顺序列出了类及其超类。MRO列表遵循C3线性化算法,它考虑了类的继承关系和方法重写,以确保方法的解析顺序是一致且合理的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class A:
def some_method( self ):
print ( "Method from class A" )
class B(A):
# def some_method(self):
# print("Method from class B")
pass
class C(A):
def some_method( self ):
print ( "Method from class C" )
class D(B, C):
# def some_method(self):
# print("Method from class D")
pass
# 创建类D的实例
d = D()
# 调用some_method()方法
d.some_method()
# 打印MRO列表
print (D.__mro__)
|
输出结果
1 2 |
# Method from class C
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
|
从结果可以看出:查找遵循了广度优先原则
三、多态
一种事物的多种形态,比如动物类会发出叫声,但是不同的动物叫声是不一样的
1、概念
允许不同的对象通过相同的接口进行交互,而无需关注对象的具体类型。多态使得我们可以编写更加灵活和通用的代码,提高代码的可重用性和可扩展性。
多态的实现依赖于继承和方法重写的机制。当多个类继承自同一个父类,并且这些子类都实现了父类的方法,那么这些子类对象可以被视为父类对象的多态形式。
多态性的关键在于子类对象可以被赋值给父类对象的变量,然后通过父类的接口来调用方法。在编译时,编译器会根据变量的声明类型选择适当的方法。而在运行时,实际上调用的是子类对象的方法。
多态实现了面向对象编程中的一个重要原则:针对接口编程,而不是针对实现编程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Animal:
def make_sound( self ):
pass
class Dog(Animal):
def make_sound( self ):
print ( "Woof!" )
class Cat(Animal):
def make_sound( self ):
print ( "Meow!" )
def make_animal_sound(animal):
animal.make_sound()
# 创建不同的子类对象
dog = Dog()
cat = Cat()
# 通过父类接口调用方法
make_animal_sound(dog) # 输出: Woof!
make_animal_sound(cat) # 输出: Meow!
|
⚠️:
1. 在此案例中Animal为父类,要求子类对象dog和cat有制造声音的功能。
2. dog和cat通过同一个接口传入,输出不同的结果
3. 此处的Animal 父类没有强制要求子类实现制造声音的功能,是一种思想,可以删掉Animal实现相同的效果
2、父类强制子类拥有相同的属性或方法
抽象类和抽象方法,用到abc模块,是abstract 抽象的英文缩写
class Animal(metaclass=abc.ABCMeta): 先变成抽象类,@abc.abstractmethod变成抽象方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 强制子类有某种属性方法
import abc
class Animal(metaclass = abc.ABCMeta):
@abc .abstractmethod
def speak( self ):
pass
@abc .abstractmethod
def run( self ):
pass
class Cat(Animal):
# def speak(self):
def test( self ):
print ( 'miaomiao' )
class Dog(Animal):
def speak( self ):
print ( 'wangwang!' )
cat = Cat()
print (cat.test())
# TypeError: Can't instantiate abstract class Cat with abstract methods run, speak
|
注:用上抽象类以后,子类没有遵循限制,实现相关的功能就会报错
1. 类传入 ‘metaclass=abc.ABCMeta’成为抽象类, 方法使用@abc.abstractmethod装饰器,成为抽象方法。
2. 抽象类本身不能被实例化和直接调用,它主要用于作为其他类的基类(父类)。
3. 抽象类的主要目的是为了定义一组通用的属性和方法,供子类继承和实现。
3、鸭子类型
抽象类的强制限制,这种方式是python不推荐的,python推荐的是鸭子类型
鸭子类型是一种思想,它关注对象的行为而不是对象的类型。
根据鸭子类型的理念,如果一个对象具有与鸭子相似的行为特征,那么它可以被视为鸭子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Duck:
def quack( self ):
print ( "Quack!" )
def fly( self ):
print ( "Flying!" )
class Robot: # 机器人
def quack( self ):
print ( "Beep!" )
def fly( self ):
print ( "Unable to fly!" )
def make_quack_and_fly(obj): # quack 嘎嘎叫声
obj.quack()
obj.fly()
duck = Duck()
robot = Robot()
make_quack_and_fly(duck) # 输出: Quack! Flying!
make_quack_and_fly(robot) # 输出: Beep! Unable to fly!
|
注:
定义了两个类,实例化一个鸭子和机器人,通过统一的函数接口调用方法(quack、fly),得到不同的结果
4、组合
一个对象拥有的属性或者方法,该属性或方法的被另外一个对象调用
案例1: 学生和选课
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
class People:
def __init__( self , name, age, gender):
self .name = name
self .age = age
self .gender = gender
class Course:
def __init__( self , course_name, course_price, course_period):
self .course_name = course_name
self .course_price = course_price
self .course_period = course_period
# 实例化课程
python = Course( "python" , 10000 , '6mon' )
linux = Course( "linux" , 20000 , '5mon' )
class Student(People):
def __init__( self , name, age, gender, course = None ):
if course is None :
course = []
super (Student, self ).__init__(name, age, gender)
self .courses = course
# def choose_course(self):
# pass
stu = Student( 'kevin' , '19' , 'male' )
stu.courses.append(python) # stu.courses ====> [python对象]
stu.courses.append(linux) # stu.courses ====> [python对象, linux对象]
# print(stu.courses)
print (stu.courses[ 0 ].course_name)
print (stu.courses[ 0 ].course_price)
|
案例2:car汽车对象使用了另一个类Engine中的函数功能,也是一种组合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class Engine:
def start( self ):
print ( "Engine started." )
def stop( self ):
print ( "Engine stopped." )
class Car:
def __init__( self ):
self .engine = Engine() # Car类包含Engine类对象
def start( self ):
print ( "Car starting." )
self .engine.start()
def stop( self ):
print ( "Car stopping." )
self .engine.stop()
car = Car()
car.start()
car.stop()
# 输出
Car starting.
Engine started.
Car stopping.
Engine stopped.
|
案例3:商品和订单的组合关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
class Product:
def __init__( self , name, price):
self .name = name
self .price = price
def info( self ):
print (f "Product: {self.name}, Price: ${self.price}" )
class Order:
def __init__( self , order_id):
self .order_id = order_id
self .products = []
# 添加商品
def add_product( self , product): # 接收一个实例对象(包括对象的所有属性和方法)
self .products.append(product)
# 展示商品
def display( self ):
print (f "商品订单: {self.order_id}" )
print ( "商品展示:" )
for product in self .products: # 实例对象列表,每次循环都是一个实例
product.info() # 商品实例调用商品对象的内部info方法,打印商品名和价格信息
print ( "-----------" )
# 创建产品,实例化过程
product1 = Product( "Phone" , 999 )
product2 = Product( "Laptop" , 1499 )
product3 = Product( "Headphones" , 199 )
# 创建订单,实例化过程
order = Order( "ORD-123" )
order.add_product(product1) # 把实例传进去
order.add_product(product2)
order.add_product(product3)
# 显示订单信息,order是一个实例对象
order.display()
|