深入类和多态

一,鸭子类型和多态

  1. 鸭子类型

    当你看到一只鸟走起来想鸭子,游泳起来像鸭子,叫起来像鸭子,那么这只鸟就叫做鸭子类型

    • 我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
    • 我们只关心一个类被不同的魔法函数赋予了不同的特性,我们看他是什么类型,是看他实现了哪些魔法函数,具有哪些特性
    • Java 里面如果要实现一个特点的类型,必须继承一个类,而 python 只需要写几个魔法函数,赋予它那种数据类型的特性就行, 这就是鸭子类型
    • 又比如 list.extend()方法中,我们并不关心它的参数是不是list,只要它是可迭代的,所以它的参数可以是list/tuple/dict/字符串/生成器等.

    例子:比方说我创建了一个类叫狗类,但是我在这个狗类里面定义了一个魔法方法,使他具有鸟的飞行能力,那么我们就称这种为鸭子类型

  2. 多态

    从语言层面上讲就已经是多态的了,背后已经帮我们实现了

    class Cat(object):def say(self):print('i am a cat')class Dog(object):def say(self):print('i am a dog')class Duck(object):def say(self):print('i am a Duck')
    
    • 三个对象都能够实现 say 方法,并且能够打印不同的内容,他们定义的方法是一样的,但功能不一样,多态

二,抽象基类(abc模块)

  • 特点
  1. 在一个基础的类中设定一些特点的方法,所有继承这个抽象基类的子类都必须实现这些方法
  2. 抽象基类不能被实例化
  • 应用
  1. 我们在某些情况下希望判定某个对象的类型

    from collections.abc import Sized
    print(isinstance(com, Sized))# 我们想判断我们实现的类是不是一个Sized的子类,那么我们必须Sized这个抽象基类的接口
    
  2. 我们需要某个子类必须实现某些方法,比方说设计一个web框架,必须设计一个抽象基类,每个继承的类都必须实现特点的几个接口,以便于用户使用的方便。

    比如数据的存入,要选择不同的数据库,我们不知道用户要用哪种,为了避免日后少改动代码和出错,不许定义一个抽象基类

  • 实现方法
  1. 在调用的时候出错,不正式

    class CacheBase():def get(self, key):raise NotImplementedErrordef set(self, key, value):raise NotImplementedErrorc = CacheBase()
    c.set('aa', 'bb')
    ...
    Traceback (most recent call last):File "D:/Python/Python笔记/python高级编程和异步IO并发编程/Code/chapter04/abc_text.py", line 50, in <module>c.set('aa', 'bb')File "D:/Python/Python笔记/python高级编程和异步IO并发编程/Code/chapter04/abc_text.py", line 47, in setraise NotImplementedError
    NotImplementedError# 我们发现上面只有在调用的时候才会出错,在用户创建的时候不会抛出异常
    
  2. 在定义类的时候,就会抛出异常,强制对象一定要实现方法

    import abcclass CacheBase(metaclass=abc.ABCMeta):@abc.abstractmethoddef get(self, key):pass@abc.abstractmethoddef set(self, key, value):passc = CacheBase()
    ...
    Traceback (most recent call last):File "D:/Python/Python笔记/python高级编程和异步IO并发编程/Code/chapter04/abc_text.py", line 56, in <module>c = CacheBase()
    TypeError: Can't instantiate abstract class CacheBase with abstract methods get, set
    
  • 实际在开发过程中,一般使用鸭子类型,如果一定要使用,建议用多继承的方法去实现
  • 抽象基类设计过度不容易理解他,所以一般是用多继承的方式来

三,isinstance和type的区别

判断一个对象的类型,用 isinstance 而不是 type

class A:passclass B(A):passb = B()
print('instance 判断b是否属于A类 =>', isinstance(b, A))
print('instance 判断b是否属于B类 =>', isinstance(b, A))
print('type 判断a是否属于A类 =>', type(b) is A)
print('type 判断a是否属于B类 =>', type(b) is B)

使用type is 判断类型会有偏差,因为 is 是判断两个对象的内存地址,不能顾及到继承,所以不推荐

内置的 isinstance 内部会有优化机制,会从对象本身,到继承一层一层忘上找,判断

四,类变量和对象变量

class Dog:tall = 20def __init__(x, y):self.x = xself.y = ydog = Dog(10, 20)
dog.tall        # 类变量
dog.x           # 实例属性
dog.y           # 实例属性,也叫对象属性

五,类和实例的查找顺序

深度算法和广度算法,C3算法

六,类方法,静态方法,实例方法

class Date():                                ①def __init__(self, year, moth, day):self.year = yearself.moth = mothself.day = daydef tomorrow(self):                       ②self.day += 1def __str__(self):                      ③return '{}/{}/{}'.format(self.year, self.moth, self.day)if __name__ == '__main__':date = Date(2019, 9, 11)print(date)

① 我们实现了一个 Date 类,并且这个类实现了三个方法

② 我们自己定义的方法,每个初始化的实例都有这个方法,我们称他为实例方法

③ 打印实例的时候回调用这个方法

如果我们传入的值是一个字符串,在输出之前要对他进行字符创的处理,我们可以使用静态方法

  • 不适用静态方法

    class Date():def __init__(self, year, moth, day):self.year = yearself.moth = mothself.day = daydef tomorrow(self):self.day += 1def __str__(self):return '{}/{}/{}'.format(self.year, self.moth, self.day)if __name__ == '__main__':date_str = '2019-12-1'year, moth, day = tuple(date_str.split('-'))date = Date(year, moth, day)print(date)
    

    我们发现,这种方法的使用比较烦,用起来不顺手

  • 使用静态方法 staticmethod

    staticmethod 的用法:把 实例方法 转换成一个函数,就是真正的函数,如果要使用,必须进入类内部

    class Date():def __init__(self, year, moth, day):self.year = yearself.moth = mothself.day = daydef tomorrow(self):self.day += 1@staticmethod                                  ①def parse_from_string(string):year, moth, day = tuple(string.split('-'))return Date(year, moth, day)@staticmethod                                  ②def string_is_date(string):year, moth, day = tuple(string.split('-'))if len(year) == 4 and len(moth) == 2 and day == 2:return Trueelse:return Falsedef __str__(self):return '{}/{}/{}'.format(self.year, self.moth, self.day)if __name__ == '__main__':date_str = '2019-12-1'date = Date.parse_from_string(date_str)print(date)
    

    ① staticmethod 的用法不在这里,这里只是演示他能实现这个功能,如果涉及和类实例相关,用classmethod

    ② 这里介绍了staticmethod 方法的主要用法

    classmethod 的用法:把第一个参数变成类对象本身,方便我们在实例之前,对数据进行处理,返回实例

    class Date():def __init__(self, year, moth, day):self.year = yearself.moth = mothself.day = daydef tomorrow(self):self.day += 1@classmethoddef parse_from_string(cls, string):year, moth, day = tuple(string.split('-'))return cls(year, moth, day)def __str__(self):return '{}/{}/{}'.format(self.year, self.moth, self.day)if __name__ == '__main__':date_str = '2019-12-1'date = Date.parse_from_string(date_str)print(date)
    

六,数据封装和私有属性

class Date():def __init__(self, year, moth, day):self.year = yearself.moth = mothself.day = daydef tomorrow(self):self.day += 1@classmethoddef parse_from_string(cls, string):year, moth, day = tuple(string.split('-'))return cls(year, moth, day)def __str__(self):return '{}/{}/{}'.format(self.year, self.moth, self.day)class User:def __init__(self, birthday):self.__birthday = birthdaydef get_age(self):# 返回年龄return 2019 - self.__birthday.yearif __name__ == '__main__':user = User(Date(1999, 12, 1))print(user.get_age())

七,python对象的自省机制

我们可以使用 __dict__ 来查看 python 类的自省机制,储存在字典里,是效率很高的数据结构

class Person:passclass Student:def __init__(self, name):self.name = nameif __name__ == '__main__':xyb = Student('xyb')print(xyb.__dict__)print(Student.__dict__)...
{'name': 'xyb'}
{'__module__': '__main__', '__init__': <function Student.__init__ at 0x000002053AC248C8>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}

如果要查找一个对象实现了所有方法,使用 dir() 函数

class Person:passclass Student:def __init__(self, name):self.name = nameif __name__ == '__main__':xyb = Student('xyb')print(dir(xyb))['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']

流畅的python 里面具体介绍了 python 的自省机制,但是如果有几十万上百万的数据要储存,要用元组,字典虽然效率极高,但是占用内存大

八,super的调用顺序

super 调用顺序为__mro__ 打印的结果

python高级编程(3) - 深入类和多态相关推荐

  1. 4万字【Python高级编程】保姆式教学,进阶感觉到吃力?学完这些就轻松了

    前几天和一个小伙子聊天时,发现了一个问题,他从零开始学Python,学完列表.字典和函数等基础之后,就开始往爬虫方向进阶学习,结果又花了一个多月的时间,啥也没学成,反而寸步难行. 其实这个问题的主要原 ...

  2. python高级编程装饰器_Python装饰器

    def my_decorator(function): def _my_decorator(*args, **kw): #在调用实际函数之前做些填充工作 res = function(*args, * ...

  3. python数据符号函数等一切皆对象_第一章:Python高级编程-Python一切皆对象

    第一章:Python高级编程-Python一切皆对象 Python3高级核心技术97讲 笔记 1. Python一切皆对象 1.1 函数和类也是对象,属于Python的一等公民 "" ...

  4. python高级编程-网络编程、多任务

    python高级编程 1 IP地址 用来在网络中标记一台电脑:在本地局域网上是唯一的. 2 端口 一个程序需要收发网络数据,就需要端口号. 3 socket 创建socket # 创建tcp sock ...

  5. Python 高级编程笔记之类别

    目录: 子类化内建类型 访问超类中的方法-super 描述符 & 属性 元编程 主要内容: 1.子类化内建类型 # -*- coding:utf-8 -*-class Folder(list) ...

  6. python队列线程池_实例详解:python高级编程之消息队列(Queue)与进程池(Pool)

    今天为大家带来的内容是:python高级编程之消息队列(Queue)与进程池(Pool),结合了实例的形式详细分析了Python消息队列与进程池的相关原理.使用技巧与操作注意事项!!! Queue消息 ...

  7. 【Python高级编程】

    Python高级编程:技巧代码的玄学与艺术 一.编程语言介绍 Python 作为一门优秀的编程语言,有着很多优势: 简单易学 Python有简单的语法,易于阅读和学习,很适合初学者.它的设计哲学是&q ...

  8. python高级编程函数_Python高级编程之十大装B语法

    for - else 什么?不是 if 和 else 才是原配吗?No,你可能不知道,else 是个脚踩两只船的家伙,for 和 else 也是一对,而且是合法的.十大装B语法,for-else 绝对 ...

  9. Python 高级编程(第2版)

    内容简介 Python 作为一种高级程序设计语言,凭借其简洁.易读及可扩展性日渐成为程序设计领域备受推崇的语言之一. 本书基于 Python 3.5 版本进行讲解,深度揭示了 Python 编程的高级 ...

最新文章

  1. Ansible 入门案例
  2. Win11系统获取管理员权限的方法
  3. MP-Ukagaka伪春菜插件扩展:在对话框用iframe显示链接
  4. AMD第三季:站在金融危机对面
  5. bjui给出的一个标准应用的首页
  6. 人工智能就是计算机科学的英语,人工智能的英语解释
  7. html文本框虚线并加上文字,文字边框虚线样式用css怎么写?(示例)
  8. 动辄上亿损失,网络安全谁来买单?
  9. avatar Logo
  10. c语言佛像怎么打,佛像的制作过程,让你大开眼界!
  11. To prevent a momery leak
  12. SEO每天都是动态变化的,你要关注什么?
  13. 今天,小灰36岁了!
  14. 队列等待之enq: TX - row lock contention
  15. 你以为越复杂的密码越安全?小心那些错误认知
  16. ES2015 import 详解
  17. PHP实现的日志收集系统
  18. 从one hot vector到Attention, Bert——NLP基本思想串连回顾
  19. java实现图片固定长宽的缩放和裁剪
  20. 二次函数顶点式计算机,二次函数顶点式是什么?

热门文章

  1. Python编程 数值类型 数学计算
  2. python github 12306 文贤平_GitHub - itsmartkit/12306-Ticket-Booking: 12306自动抢票系统(2020-01-10)...
  3. 查看局域网计算机要输入密码,为什么访问局域网内的计算机总是要求输入密码...
  4. SPI总线和外设驱动(一)
  5. Jquery——一些笔记
  6. 形容计算机水平的句子,形容专业水平高的句子大全 精于专业的名言警句
  7. 视频缓存文件(.tdl)合并为新的视频文件(.mp4)
  8. 【爬虫系列】Python如何实现进度条效果?
  9. 与符号表分离程序或动态库, 如何用GDB调试
  10. wps宏编程js宏编辑器之代码调试讲解