一、封装
封装是一种将数据和相关方法组合成一个单独的实体的机制。它将数据(属性)和操作数据的方法(方法)封装在一个对象中,并对外部代码隐藏了内部的实现细节。通过封装,对象可以提供一个公共接口,使得外部代码可以通过该接口访问和操作对象的数据,而不
需要了解其内部的具体实现。
二、继承
继承是新建类的一种方式,新建出来的类称作子类,被继承的类叫父类
它允许新类(子类)继承现有类(父类)的属性和方法,并且可以在新类中添加新的属性和方法,或者重写父类的方法来定制子类的行为。
继承促进了代码的重用和扩展(),并且提供了层次化和组织化的代码结构。解决了类与类之间的代码冗余问题
1、为什么要继承?
类解决什么问题:解决的是对象与对象之间的代码冗余问题
继承解决什么问题:解决的是类与类之间的代码冗余问题
2、子类的继承可以有多个父类
class Parent1(object):
pass
class Parent2:
pass
# 子类
class Sub1(Parent1):
pass
# 多继承, 括号里面可以写多个类
class Sub2(Parent1, Parent2):
pass
3、查看一个类继承了哪些父类,.__bases__方法
print(Sub1.__bases__) # (<class '__main__.Parent1'>,) print(Sub2.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>) print(Parent1.__bases__) # (<class 'object'>,)
注:python3中新定义的父类默认继承的是object类,所以父类也是一个子类
4、继承小案例
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、多
菱形查找分:经典类和新式类
经典类:按照深度优先查询
新式类:按照的广度优先查询
非菱形查找

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,形成菱形查找
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()方法来实现派生与方法重用:
指名道姓的调用某一个类的函数(不依赖于继承)
派生:比父类多的功能,派生方法。
相同的方法:重写
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线性化算法,它考虑了类的继承关系和方法重写,以确保方法的解析顺序是一致且合理的。
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__)
输出结果
# Method from class C # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
从结果可以看出:查找遵循了广度优先原则
三、多态
一种事物的多种形态,比如动物类会发出叫声,但是不同的动物叫声是不一样的
1、概念
允许不同的对象通过相同的接口进行交互,而无需关注对象的具体类型。多态使得我们可以编写更加灵活和通用的代码,提高代码的可重用性和可扩展性。
多态的实现依赖于继承和方法重写的机制。当多个类继承自同一个父类,并且这些子类都实现了父类的方法,那么这些子类对象可以被视为父类对象的多态形式。
多态性的关键在于子类对象可以被赋值给父类对象的变量,然后通过父类的接口来调用方法。在编译时,编译器会根据变量的声明类型选择适当的方法。而在运行时,实际上调用的是子类对象的方法。
多态实现了面向对象编程中的一个重要原则:针对接口编程,而不是针对实现编程。
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变成抽象方法
# 强制子类有某种属性方法
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推荐的是鸭子类型
鸭子类型是一种思想,它关注对象的行为而不是对象的类型。
根据鸭子类型的理念,如果一个对象具有与鸭子相似的行为特征,那么它可以被视为鸭子。
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: 学生和选课
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中的函数功能,也是一种组合
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:商品和订单的组合关系
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()




