python

 
面向对象设计
  • 对象是什么——数据与相关行为的集合。简单来说,它们是一些东西的模型,可以做同样的特定行为或被特定事物所影响
  • 面向对象——功能性地指向建模对象,通过数据和行为来描述一系列相互作用的对象
  • 面向对象分析、设计和编程
    • 分析、设计和编程是面向对象的三个不同阶段
    • 分析阶段是针对任务确定其中对象与对象之间的交互关系的过程,关注的是——需要完成什么,输出的是一系列需求
    • 设计阶段是将需求转化为实现方案的过程,关注的是——如何完成,输出的是实现方案,即将需求转化为一系列的类和接口
    • 编程阶段是将完美定义的设计转化为可运行程序的过程
基本原则
  • 组合——组合是将几个对象收集在一起生成一个新对象的行为
    • 聚合
继承
  • 对象和类
    • 图例
      notion imagenotion image
      notion imagenotion image
      notion imagenotion image
      notion imagenotion image
      notion imagenotion image
    • 对象是数据及其相关行为的集合
    • 类是用来描述对象的,是实现对象的蓝图
    • 对象是一些可以相互关联的类的实例
    • 对象实例是拥有自己的数据和行为的特定对象
    • 数据通常代表一个特定对象的个体特征,用以描述对象
    • 类可以定义一系列属于这一类对象所共有的特征
  • 面向对象的分析与设计的目的——弄清对象是什么以及它们之间如何交互
  • 公共接口
    • 模型是对真实概念的一种抽象
    • 抽象意味着只处理与给定任务相关的最必要的一层细节,是从内部细节中提取公共接口的过程
    • 封装(信息隐藏)
    • 继承
    • 多态(鸭子类型)
Python对象
  • 给类和方法添加解释,通过注释的方式添加,通过help()函数可以展示相应的Python字符串解释
  • 方法与函数:对象中的叫做方法,单拎出来就是函数
  • 理论上Python中数据存在可访问不可访问的区分,实际上Python中的所有数据都是可访问的
    • 通常以下划线开头的属性表示为私有属性,不应该被外部访问。
    • 特别地,当使用双下划线开头的方式进行命名时,Python对该属性起别名(加上 _<类名>的前缀),在内部两种名称都可访问该属性,但在外部只能通过别名访问该属性
  • 模块就是Python文件
  • 一个包就是一个目录下模块的集合
  • 导入包和模块
    • 绝对导入——使用完整路径导入
    • 相对导入
      • 如果我们想在 products 模块中导入与之相邻的database 模块的 Database 类
      • database 前面的点号的意思是“使用当前包内的 database 模块”
      • 如果我们正在编辑 ecommerce.payments 包中的 paypal 模块,可能想要“使用父包中的 database 包”。可以非常方便地用两个点号来实现,
  • 组合关系——在一个类对象中使用另一个类对象,通常被使用的类对象是容器对象
对象相似时
基本继承
  • 在基类的基础上扩展功能
  • 示例
    • 现有联系人管理器,由Contact类生成联系人对象。在此基础上,有的联系人可能也是供货商,只有供货商才能提供货物,此时由Suppier类通过继承Contact类,并实现自己的方法。
    • 这样:由Contact类产生的对象都是联系人;由Supplier类产生的对象不仅是联系人,也是供货商,拥有独属于供货商的方法
  • 子类继承父类的所有方法和属性,同时也可重写父类的方法以及新增自己的方法和属性
  • super()方法可以使子类寻找并调用超类中指定的方法(即调用MRO列表中上一个类的方法,此处的MRO列表指的是初次调用super方法的类),如果超类中不存在该方法则会报错
多重继承
  • 多重继承指的是一个子类继承多个父类,但继承父类的顺序必须符合单调性规则——子类在父类之前
  • 多重继承最简单有效的方式被称为混入(mixin)
    • 混入类是一个不会单独存在的超类,而是会被其他类继承以期望添加额外功能的类
  • Python会根据C3算法自动计算出MRO(方法执行顺序)列表
    • MRO列表符合单调性规则
    • super()方法的链式调用遵从MRO列表的顺序
多态——由于所用子类不同而产生的不同行为,而不需要明确知道用的是哪个子类(不同类的对象对于相同方法的调用可以表现出不用的行为)
  • 简单来说,多态允许以统一的方式处理不同类型的对象,只要它们遵从同样的接口或继承自相同的抽象基类
如下,使用多媒体播放器时可直接播放支持的文件,其背后的AudioFile类中的 __init__()访问了子类中的类变量ext,但并没有存储ext变量的引用
# 多媒体播放器 class AudioFile(): def __init__(self, filename: str): if not filename.endswith(self.ext): raise Exception('Invalid file format') self.filename = filename class MP3File(AudioFile): ext = 'mp3' def play(self): print(f'playing {self.filename} as mps.') class WavFile(AudioFile): ext = 'wav' def play(self): print(f'playing {self.filename} as wav.') class OggFile(AudioFile): ext = 'ogg' def play(self): print(f'playing {self.filename} as ogg.')
鸭子类型
  • 如果它走像鸭子、游泳像鸭子,那么它就是一只鸭子”。我们不关心它是否真的是一只(继承自)鸭子,只需要知道它可以游泳或走路即可
  • 特征——鸭子类型的对象只需要提供真正被访问的方法和属性(即不需要提供所需对象的所有接口,而只需要满足实际被访问的接口)
抽象基类
  • 抽象基类,定义一组必须被类的鸭子类型实例实现的方法和属性。本身不提供完全的方法实现,而是提供一个或多个抽象方法,这些方法没有实现内容(即没有具体的代码)
    • 在创建子类时,必须实现抽象基类中的这些抽象方法,否则子类将成为抽象类,不能被实例化
    • 可以继承抽象基类本身的类来作为类的实例,但是必须提供所有合适的方法
  • Container 类(容器类抽象基类)
    • 任何实现它的类都需要实现 __contains__()方法,并且都可以用 in 关键字查询
      • 实际上,in 是 __contains__() 方法的语法糖
    • 如果需要测试一个对象是否为一个容器类型,可以直接检查它是否实现了 __contains__ 方法:
    • if hasattr(your_object, '__contains__'): print("This is a container") else: print("This is not a container")
  • 创建抽象基类
    • python 3.4 之前通过指定元类的方式告诉Python这是一个抽象基类
    • python 3.4 之后新增了简化方法 from abc import ABC ,通过继承 abc,ABC 类告诉Python这是一个抽象基类。
    • 两种方法定义的抽象基类在功能上是相同的,只是语法上有所不同。
    • # 法一:指明元类 import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def speak(self): pass # 法二:继承 abc.ABC 类 from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def speak(self): pass class Dog(Animal): def speak(self): return "Wof!" class Cat(Animal): def speak(self): return "Meow!"
  • 抽象基类常常与多态一起使用,但它们描述的是不同的概念
    • 抽象基类确定了一个通用的模板,要求派生类必须提供某些方法的实现。
    • 多态指的是程序能够使用这些不同的派生类对象,并且在运行时根据实际对象的类型来选择合适的方法进行调用。
    • 因此,可以说抽象基类是一种机制,用于定义多态性质的接口;而多态则是一种通过这些接口在运行时做出选择的概念。抽象基类是实现多态的一种方式,但不是唯一方式。在某些情况下,接口(在一些静态类型语言中)或鸭子类型(在像Python这样的动态类型语言中)也可以用来实现多态性。
案例学习-简单的房地产应用
 
对于本文内容有任何疑问, 可与我联系.