python高级编程(3) - 深入类和多态
深入类和多态
一,鸭子类型和多态
鸭子类型
当你看到一只鸟走起来想鸭子,游泳起来像鸭子,叫起来像鸭子,那么这只鸟就叫做鸭子类型
- 我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
- 我们只关心一个类被不同的魔法函数赋予了不同的特性,我们看他是什么类型,是看他实现了哪些魔法函数,具有哪些特性
- Java 里面如果要实现一个特点的类型,必须继承一个类,而 python 只需要写几个魔法函数,赋予它那种数据类型的特性就行, 这就是鸭子类型
- 又比如 list.extend()方法中,我们并不关心它的参数是不是list,只要它是可迭代的,所以它的参数可以是list/tuple/dict/字符串/生成器等.
例子:比方说我创建了一个类叫狗类,但是我在这个狗类里面定义了一个魔法方法,使他具有鸟的飞行能力,那么我们就称这种为鸭子类型
多态
从语言层面上讲就已经是多态的了,背后已经帮我们实现了
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模块)
特点
- 在一个基础的类中设定一些特点的方法,所有继承这个抽象基类的子类都必须实现这些方法
- 抽象基类不能被实例化
应用
我们在某些情况下希望判定某个对象的类型
from collections.abc import Sized print(isinstance(com, Sized))# 我们想判断我们实现的类是不是一个Sized的子类,那么我们必须Sized这个抽象基类的接口
我们需要某个子类必须实现某些方法,比方说设计一个web框架,必须设计一个抽象基类,每个继承的类都必须实现特点的几个接口,以便于用户使用的方便。
比如数据的存入,要选择不同的数据库,我们不知道用户要用哪种,为了避免日后少改动代码和出错,不许定义一个抽象基类
实现方法
在调用的时候出错,不正式
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# 我们发现上面只有在调用的时候才会出错,在用户创建的时候不会抛出异常
在定义类的时候,就会抛出异常,强制对象一定要实现方法
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) - 深入类和多态相关推荐
- 4万字【Python高级编程】保姆式教学,进阶感觉到吃力?学完这些就轻松了
前几天和一个小伙子聊天时,发现了一个问题,他从零开始学Python,学完列表.字典和函数等基础之后,就开始往爬虫方向进阶学习,结果又花了一个多月的时间,啥也没学成,反而寸步难行. 其实这个问题的主要原 ...
- python高级编程装饰器_Python装饰器
def my_decorator(function): def _my_decorator(*args, **kw): #在调用实际函数之前做些填充工作 res = function(*args, * ...
- python数据符号函数等一切皆对象_第一章:Python高级编程-Python一切皆对象
第一章:Python高级编程-Python一切皆对象 Python3高级核心技术97讲 笔记 1. Python一切皆对象 1.1 函数和类也是对象,属于Python的一等公民 "" ...
- python高级编程-网络编程、多任务
python高级编程 1 IP地址 用来在网络中标记一台电脑:在本地局域网上是唯一的. 2 端口 一个程序需要收发网络数据,就需要端口号. 3 socket 创建socket # 创建tcp sock ...
- Python 高级编程笔记之类别
目录: 子类化内建类型 访问超类中的方法-super 描述符 & 属性 元编程 主要内容: 1.子类化内建类型 # -*- coding:utf-8 -*-class Folder(list) ...
- python队列线程池_实例详解:python高级编程之消息队列(Queue)与进程池(Pool)
今天为大家带来的内容是:python高级编程之消息队列(Queue)与进程池(Pool),结合了实例的形式详细分析了Python消息队列与进程池的相关原理.使用技巧与操作注意事项!!! Queue消息 ...
- 【Python高级编程】
Python高级编程:技巧代码的玄学与艺术 一.编程语言介绍 Python 作为一门优秀的编程语言,有着很多优势: 简单易学 Python有简单的语法,易于阅读和学习,很适合初学者.它的设计哲学是&q ...
- python高级编程函数_Python高级编程之十大装B语法
for - else 什么?不是 if 和 else 才是原配吗?No,你可能不知道,else 是个脚踩两只船的家伙,for 和 else 也是一对,而且是合法的.十大装B语法,for-else 绝对 ...
- Python 高级编程(第2版)
内容简介 Python 作为一种高级程序设计语言,凭借其简洁.易读及可扩展性日渐成为程序设计领域备受推崇的语言之一. 本书基于 Python 3.5 版本进行讲解,深度揭示了 Python 编程的高级 ...
最新文章
- Ansible 入门案例
- Win11系统获取管理员权限的方法
- MP-Ukagaka伪春菜插件扩展:在对话框用iframe显示链接
- AMD第三季:站在金融危机对面
- bjui给出的一个标准应用的首页
- 人工智能就是计算机科学的英语,人工智能的英语解释
- html文本框虚线并加上文字,文字边框虚线样式用css怎么写?(示例)
- 动辄上亿损失,网络安全谁来买单?
- avatar Logo
- c语言佛像怎么打,佛像的制作过程,让你大开眼界!
- To prevent a momery leak
- SEO每天都是动态变化的,你要关注什么?
- 今天,小灰36岁了!
- 队列等待之enq: TX - row lock contention
- 你以为越复杂的密码越安全?小心那些错误认知
- ES2015 import 详解
- PHP实现的日志收集系统
- 从one hot vector到Attention, Bert——NLP基本思想串连回顾
- java实现图片固定长宽的缩放和裁剪
- 二次函数顶点式计算机,二次函数顶点式是什么?
热门文章
- Python编程 数值类型 数学计算
- python github 12306 文贤平_GitHub - itsmartkit/12306-Ticket-Booking: 12306自动抢票系统(2020-01-10)...
- 查看局域网计算机要输入密码,为什么访问局域网内的计算机总是要求输入密码...
- SPI总线和外设驱动(一)
- Jquery——一些笔记
- 形容计算机水平的句子,形容专业水平高的句子大全 精于专业的名言警句
- 视频缓存文件(.tdl)合并为新的视频文件(.mp4)
- 【爬虫系列】Python如何实现进度条效果?
- 与符号表分离程序或动态库, 如何用GDB调试
- wps宏编程js宏编辑器之代码调试讲解