Web高阶课堂笔记4(python元类及迭代器生成器)

_getattr _ 与 _ getattribute _魔法函数

_getattr _魔法函数

_getattr _:是当类调用一个不存在的属性时才会调用getattr魔法函数,他传入的值哦那个item就是你这个调用的不存在的值。

如下图所示:user.age:是个不存在的属性。要解决方法一:在user类中添加age属性。
在这里插入图片描述方法二:使用getattr魔法函数。那么此时魔法方法_getattr _(self, item):中的item就自动对应不存在的属性。此处对应age。当age这个属性不存在的时候触发执行getattr魔法方法的内容。同时,不存在的属性返回值为空值(None)。
在这里插入图片描述在这里插入图片描述

_getattribute _:无条件的优先执行,所以如果不是特殊情况最好 不使用 _ getattribute _。

_ getattribute _方法的优先级比原先存在的属性方法优先级还要高,所以会造成存在的属性也进入 getattribute方法中被执行,造成不正确性。
在这里插入图片描述
而使用getattr方法则不会存在这种情况,如下图所示:
在这里插入图片描述

属性描述符

属性描述符介绍

属性描述符一个强大的通用协议。是properties、methods、static、methods、classmethods和super()的调用原理。

属性描述符协议

属性描述符是实现了特定协议的类。只要实现了_get _、 _set _、 _delete _三个方法中的任意一个,这个类就是描述符,它能实现对多个属性运用相同存取逻辑的一种方式【创建一个实例作为另一个类的类属性】

当一个或者多个类都需要重复调用同一种设置的时候,通过一个类的属性描述符设置【后续称为描述符类】,后续通过将描述符类实例化后,可以在别的类中调用需要重复调用的内容,减少反复度。

注意:

  • 一个对象同时定义了 get 和set 方法,被称为数据描述符(data descriptor)
  • 只定义 get 方法的对象被称为非数据描述符(non-data descriptor)

属性描述符使用:
在一个类中定义属性描述符三种方法中的任意一个或者几个。
在这里插入图片描述
在别的类中调用属性描述符类【将属性描述符的类实例化】
在这里插入图片描述
在这里插入图片描述

练习:

当动态绑定属性时,判断该属性值是否为int类型。 是,则赋值。 不是,则主动抛出异常。
在这里插入图片描述

property()也是可以轻松将任意属性创建可用的描述符

注意是 property()方法 而不是@property装饰器。
property(fget=None, fset=None,fdel=None, doc=None)

描述符查找顺序

当为数据描述符时【set和get都存在的情况】:get魔法方法 优先级高于 dict【字典形式返回属性值】魔法方法
在这里插入图片描述

当为非数据描述符时【只有get存在,没有set】dict魔法方法优先级高于get魔法方法。

当没有set魔法方法的时候使用实例属性赋值不会造成set 和dict动态绑定属性优先级问题。所以dict优先于get魔法方法,执行时候优先执行dict动态绑定后的值。

创建元类

元类介绍

元类实际上就是创建类的类

说明如下:
动态创建类实例【这个方法不方便,代码过于重复还不够灵活】。就使用type创建类
创建一个类的函数create_class在这里插入图片描述
如果给create_class类传入参数user ,则创建user类。
在这里插入图片描述
创建实例调用user类
在这里插入图片描述

使用type创建类

在这里插入图片描述
上图中type(ojbect):返回对象的类型
type(name,bases,dict):创建新类
name:类名【字符串形式】
bases:由父类组成的元组
dict:字典形式{},定义属性和方法的。字典的key:属性名,value:属性值
在这里插入图片描述

添加属性

注意:type的第三个形参,字典中传入的key值‘age’是指类属性
在这里插入图片描述

添加方法

在外部创建方法,之后传入type第三个形参中。
在这里插入图片描述

添加静态方法(有装饰器的方法)

在外部定义方法的时候直接在方法上装上装饰器,在传入type第三个形参中。
在这里插入图片描述
注意:
实例方法要写入self参数。静态方法不需要写入参数。类方法一定要有cls参数。

添加属性小结

添加方式基本于在类的内部定义方式一致。
只不过需要在type()的第三个形参通过字典进行类于方法名绑定。

字典:
key:属性名
value:属性值

type创建的类的继承方式

单继承 在type第二个形参元组中传入父类的名字,就能继承父类。
注意:父类名字后面必须跟逗号【元组内如果是一个元素后面必须跟逗号】
在这里插入图片描述

多继承的查询顺序还是根据左边优先等多继承原则
在这里插入图片描述

metaclass属性

metaclass属性介绍

如果一个类中定义了_metalass _=xxx python就会用元类的方式来创建类,就可以控制类的创建行为。【支持自定义一个类,使它是后面某一个类的元类】

metaclass使用

1、创建Myclass类,传入‘metaclass=xxx’的参数。这次传入upper_attr 方法。
在这里插入图片描述
2、创建upper_attr函数
在这里插入图片描述
在这里插入图片描述
因为发现上图中upper_attr的形参打印数据和type元类创建中的形参基本一致,所以可以实现type创建元类,同时设置返回值。

3、返回type创建的类
在这里插入图片描述
4、将cls_attr中的属性名规定为大写后访问。注:大写的属性名指类属性,而非以’_ _'开头的属性名。

方式:遍历取出属性,将非_ 开头的属性名取出转为大写。
在这里插入图片描述
5、因为遍历后将属性名大写访问放入了新的字典中,所以返回值中type参数cla_attr需要修改成新的字典名。
在这里插入图片描述

metaclass查找顺序

被metaclass=xxx的类那个xxx的类是被优先查找的。
在这里插入图片描述
同时注意:元类中new的继承参数要全写。

补充

元类的创建传入的三个参数因为与type一致,所以直接继承type即可看作元类。Myclass(type)这个类就是元类。
在这里插入图片描述
此时new类传参是通过type创建类时所需要传入的参数,而不是*args和**kwargs

所有类的根本来源就是type,而type的根本来源就是自身。如下图所示:
在这里插入图片描述

元类能拓展新的功能

比如列表不能使用add进行内容添加,只可以append。但是通过元类可以使列表能add添加。
在这里插入图片描述
添加一个add的属性,底层还是通过append方法实现的,但是通过add属性调用的而已。

涉及类属性变更和类创建的时候控制实例的创建

_ call_:将类实例当作函数调用。
在实例化的变量名后面加上() ,当成函数方法的调用去使用才能调用实例。
在这里插入图片描述
当几个类都有同一个方法的时候,可以设置一个类调用这几个类中的佛能给一个方法。此方法称为工厂。

通过这个工厂类继承元类,可以限制不通过工厂类来执行方法的步骤,必须通过工厂返回实例。

迭代器与生成器

  • 生成器可以做到迭代器能做的所有事
  • 因为生成器自动创建了iter()和next()方法,所以生成器显得简洁而去高效

迭代器

迭代器指:迭代取值的工具,迭代是指一个重复的过程,每一次重复都是基于上一次结果而来

迭代提供了一种通用的不依赖索引的迭代取值方式。

可迭代对象

可以用for循环遍历的对象都是可迭代对象

  • str、list、tuple、dict、set等都是可迭代对象
  • generator, 包括生成器和带yield的生成器函数
判断是否可迭代

除了查看内置是否含有_iter _方法来判断该对象是否是一个可迭代对象之外。还能使用**isinstance()**判断是否是iterable对象。

isinstance():用来判断对象是否是相应类型,此处判断 iterable类型。

从collections文件【隐藏文件,详情见abc模块笔记】中导入 iterable
在这里插入图片描述

迭代器对象
  • 有内置的_next _()方法的对象,执行该方法可以不依赖索引取值
  • 有内置的_iter _()方法的对象,执行迭代器的_iter _()方法得到的依然是迭代器本身

从collections文件【隐藏文件,详情见abc模块笔记】中导入iterator

注意:
可迭代对象 不一定是 迭代器。
基本上含有next() 方法的都能被称为迭代器。
可迭代对象含有iter()方法。

iter ()方法

lier(转换的对象):将可迭代对象转为迭代器

可以被 next() 函数调用并不断返回下一个值的对象称为迭代器:iterator

可以通过iter ()方法将可迭代对象转为迭代器

通过next()方法取迭代器中的数值。但是超过迭代器数据长度【范围】会报错。
在这里插入图片描述
注意:
1、基本很少使用next()方法取迭代器的值。一般通过for遍历取值。
2、next()方法只能顺延调用,不能往前读取。

可迭代对象与迭代器区别
  • 可以用for循环的都是可迭代类型。
  • 作用于next()都是迭代器类型(iterator)。
  • list、dict、str等都是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转为迭代器。
  • python的for循环本质就是通过不断调用next()函数实现的。

生成器

生成器定义

在python中,一边循环一遍计算的机制,称为生成器:generator。

为什么要有生成器

列表所有数据都在内存中,如果有海量数据的话会非常消耗内存。【比如:当只需要访问前面前面几个元素,这时候后面的大多元素都占用内存产生了内存浪费情况。】

那么生成器就是在循环过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省空间。

生成器就是我们想要庞大的数据同时占用空间少时使用的。

创建生成器
生成器的表达式

方法一:()

生成器表达式源于迭代和列表解析的组合。生成器和列表解析类似。但是它使用( )而不是[ ]。
也是通过next()方法取值,只可以顺延,不能往前读取,同时,超过取值范围会报错。
在这里插入图片描述
方法二:yield 关键字

当一个函数中包含yield关键字,那么这个函数就不再是一个普通的函数,而是一个generator(生成器)。

下图中解释说明yield 的执行顺序:
红框执行顺序:
先触发- -func start—
之后进入for循环,先打印了 - -1—
之后打印了yield b的内容。此时b为1【此处为定义的1】
之后就不再往下执行。

黄框执行顺序:
从yield b 之后开始执行
先- -2- - ,再 - -3 - -
再度循环到 - -1- -
之后重新遇到yield b
打印b 。此时的b还是为1,不过是0+1的1,而不是定义的1
在这里插入图片描述
注意⚠️:yield返回一个值,并且记住这个返回值的位置,下次遇到next()调用时,代码从yield的下一条语句开始执行。与retum的差别是retum也是返回一个值,但是直接结束函数。

send():send()和next()一样,都能让生成器继续往下走(遇到yield返回),但send()能传一个值,这个值作为yield表达式整体的结果。

生成器使用场景
场景1 斐波那契数列计算

详情见之前基础笔记生成器篇。

类似斐波那契数列运算。根据需求执行到需要的数字。后续的不会自动执行。

场景2 求内容或者数列位置

给定一个list 和指定的数字。求这个指定的数字在list的位置

lidt = [1,3,9,11,90,9] 求数字9的位置
先根据for循环思路思考。

思路:
创建一个函数。通过传入一个列表的值和一个需要求的数字的值两个实参得到结果。
在这里插入图片描述
思路:
利用for循环遍历,将传入的值遍历得到想要的元素对应的下标,并且返回下标数。

遇到问题:返回的不是下标数,而是元素值变成了下标数,引发超出范围的报错,同时也不是正确的元素对应下标数。
在这里插入图片描述
解决方案: index()方法。读取第一个元素对应的下标数。

遇到问题:当同个数字出来多次的时候只返回了第一次下标数。
在这里插入图片描述
解决方法:遇到第一次就返回后,之后的结果都不会再运行,因为已经return结束了。创建一个空列表,统一接受下标数字后,直接返回这个结果列表。

遇到问题:列表的下标数是同一个。并不是同一个数在不同位置对应的下标数。
在这里插入图片描述
解决思路:因为 index()方法,只读取第一个元素对应的下标数。后面的相同元素的下标不会读取。

用enumerate()方法:读取元素和对应的下标数。
在这里插入图片描述在这里插入图片描述
通过生成器,将不需要列表就能解决。
在这里插入图片描述

读取大文件

通过’|'分割符,将一个大文件比如300g的txt文件内容每行分割出来。现在只要分割的内容 不要分割符。比如123|345。现在只要123 345
在这里插入图片描述
编辑函数readlines。设置读取方式
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值