Python的三个“工件”(迭代器、生成器、装饰器),python,神器,器造个,噢,曼来,打,怪兽

发表时间:2021-05-11

文章目录

迭代器

1.迭代

迭代就是一个循环 ,python中用于访问序列结构数据的一种方式。
当我们用一个循环(比如for循环)去遍历容器(列表,元组)中的数据【序列结构的数据】,这种遍历过程就叫迭代。

list1 = [1,2,3,4,5,6]
for i in list:
	print(i)

2.可迭代对象

顾名思义,就是可以被迭代的对象。也就是也已被for循环遍历的对象。
列表和元组是内置的可迭代对象。
可迭代对象中需要实现_iter_或者_getitem_方法。其中一个实现就可以是可迭代对象了,两个也行。我们能用下面方法判断是否是可迭代对象【 注意类名和迭代器的类名不一样的】

# Iterable就是一个可判断是否是可迭代对象的类     isinstance()是判断方法 第一参数是方法,第二个参数是类
from collections.abc import Iterable
print(isinstance(list(),Iterable))
print(isinstance(tuple(),Iterable))
print(isinstance(dict(),Iterable))
#可以试着在编辑器里面调用这两个方法看有没有来判断是不是可迭代对象
l1 = [1,2,3,4,5]
l1.__iter__()
》》》》》》:
True
True
True

Process finished with exit code 0

3.迭代器【iterator】

迭代器是指遵循迭代器协议(iterator protocol)的对象

(1)迭代器协议:实现对象的 _iter_,_next_ 方法, _iter_ 返回迭代器本身, next 方法返回容器下一个元素,在没有后续元素时,抛出 StopIteration 异常。
(2)可迭代对象不是迭代器,迭代器是可迭代对象
(3)使用 iter() 获得迭代器对象
#list()列表是可迭代对象但不是迭代器,判断方法true是迭代器,flase不是迭代器   Iterator迭代器类 Iterable可迭代对象类
from collections.abc import Iterator,Iterable
print(isinstance(list(), Iterator))
#通过iter()方法获得列表迭代器对象
print(isinstance(iter(list()), Iterator))
#列表迭代器是可迭代对象
print(isinstance(iter(list()), Iterable))
》》》》》》
False
True
True

Process finished with exit code 0
(4)迭代器是一个 可以记住遍历位置 的类

迭代器对象从集合的第一个元素开始访问( next() ),只能向前访问,不能后退,只到所有的元素被访问完。就和遍历数据库返回集的操作一样。

li = iter([1,2,3,4])
print(type(li))
print(next(li))
print(next(li))
# next()方法实际是调用_next_()方法来取值的
print(li.__next__())
print(next(li))
#不能用可迭代对象下标取值来取迭代器的值
print(li[1])
》》》》》
Traceback (most recent call last):
  File "D:\python\数据分析与可视化\判断迭代.py", line 23, in <module>
    print(li[1])
TypeError: 'list_iterator' object is not subscriptable
<class 'list_iterator'>
1
2
3
4
(5)迭代器不能用下标取值
## 取值最后去完会抛出该异常 try catch捕获一下就可以了
<class 'list_iterator'>
1
2
3
4
Traceback (most recent call last):
  File "D:\python\数据分析与可视化\判断迭代.py", line 22, in <module>
    print(next(li))
StopIteration
(6)迭代器会一次把所有数据都加载进内存,对内存不友好

生成器【generator】

1.生成器是一类特殊的迭代器
2.生成器在迭代时可以返回一个或多个值, 可以记录当前状态 ,【解决迭代器的对内存不友好的缺点】
3.生成器的创建
(1)使用生成器表达式【推导式】创建

列表推导式: [i表达式 for i in range(n)] 【注:元组没有推导式,集合,列表,字典都有的】
生成器表达式: (i表达式 for i in range(n))

from collections.abc import Generator
g = (i*2 for i in range(10))
print(type(g))
print(isinstance(g,Generator))
>>>>>>>>>>>
><class 'generator'>
True

Process finished with exit code 0
(2)用关键字yield: yield function
执行过程:

使用yield声明函数为生成器,当程序执行到yield处时,生成器函数暂停,等待下一次唤醒【 next(),send() 】并且返回当前值,和return相似,但程序是暂停不是结束。

#程序从g=fib(5)开始,调用函数fib()执行到yield,生成器,暂停跳出到g=fib(5),等待唤醒
def fib(n):
    current=0
    num1,num2 = 0,1
    while(current<n):
        num = num1
        num1,num2 = num2, num1+num2
        current +=1
        yield num
    return "done"
g = fib(5)
print(type(g))
》》》》》》》
<class 'generator'>

Process finished with exit code 0
4.生成器的取值: next() send()

next() 取下一个值, send() 在取一个值的同时给生成器传递一个值,它是生成器的方法, next()=send(None) ,两者可以混用, 第一次取值send()发送的值必须是None,

5.关系

在这里插入图片描述

装饰器

1.闭包
(1)概念:

是由函数及相关的引用环境组合而成的实体。

(2)python闭包形式:

不同编程语言实现闭包的形式是不一样的,python中的闭包从表现上看,是在一个内部函数对在外部作用域(不是在全局作用域)的变量的引用,那么内部函数就被认为是闭包。

def fun(x):
	def inner(y):
		return x+y
return inner
(3)注意:

闭包不可以 直接 修改外部函数的局部变量,类似于不能直接在函数中修改全局变量(可变类型除外)一样,需要使用关键字 nonlocal

(4)闭包的作用

当闭包执行完后,任然能够 保存当前的运行环境 ;闭包可以根据外部作用域的局部变量得到不同的结果。

#func1的参数是一个函数  在不改变func2代码的情况下  添加了一个打印func1的功能
def func1(func):
    def inner():
        print("func1")
        func()
    return inner
def func2():
    print("func2")
func1(func2())
2.装饰器
(1).装饰器的概念:

装饰器本质上就是一个python函数,在 不改变代码结构的情况下添加新的功能

@装饰器函数名称
def func()
	pass
(2).装饰器工作过程:

将被装饰的函数当作参数传递给装饰器函数(名称相同的函数),并返回装饰后被装饰的函数。

(3).装饰器是一种闭包的应用
(4).装饰器的使用【可以装饰函数和类】
def light(func):
    print("获得变身棒!")
    def dijia():
        func()
        print("变身迪迦!")
    return dijia
def person():
    print("我是队员:")
light(person)()
>>>>>>>>>>>
获得变身棒!
我是队员:
变身迪迦!

Process finished with exit code 0

这个写法算是闭包----》转换成装饰器的写法【可以有很多不同的person】:

def light(func):
    print("获得变身棒!")
    def dijia():
        func()
        print("变身成迪迦!")
    return dijia
@light
def person():
    print("我是队员!")
person()
》》》》》》》
获得变身棒!
我是队员!
变身成迪迦!

Process finished with exit code 0
(5).装饰器会丢失一部分信息

【就像大古变身后队友就不知道他是大谷了】
被装饰函数的原信息会丢失,如:名字,文档字符串,注解和参数签名

#函数中的文档字符串丢失  help时出来的是dijia()
def light(func):
    print("获得变身棒!")
    def dijia():
        func()
        print("变身成迪迦!")
    return dijia
@light
def person():
    """   文档字符串      """
    print("我是队员!")
person()
help(person)
》》》》》》》
获得变身棒!
我是队员!
变身成迪迦!
Help on function dijia in module __main__:

dijia()


Process finished with exit code 0

原因是由于执行过程导致的 :从程序最上面开始执行,遇到def light(func)往下到@light时,先查看下面是不是函数或者类,把下面的person函数当作参数传递到light这个函数中,执行light函数;打印 获得变身棒 ;执行dijia()内部函数,先执行person()这个参数函数即打印 我是队员 ,然后打印 变身成迪迦 ;最后跳出内部函数,返回dijia.

(6).通过装饰器来解决装饰器会丢失信息的问题

python自带的装饰器: wraps 为了保留因为使用装饰器而丢失的信息,用法如下:

from functools import wraps
def light(func):
    print("获得变身棒!")
    @wraps(func)
    def dijia():
        func()
        print("变身成迪迦!")
    return dijia
@light
def person():
    """   文档字符串      """
    print("我是队员!")
person()
help(person)
》》》》》》》
获得变身棒!
我是队员!
变身成迪迦!
Help on function person in module __main__:

person()
    文档字符串


Process finished with exit code 0

(7).被装饰函数带参数

内函数拥有对应的参数就可以解决

from functools import wraps
def func1(func):
    print("func1函数")
    @wraps(func)
    def inner(a,b):
        print("func1函数的内部函数")
        func(a,b)
    return inner
@func1
def func2(a,b):
    print(a+b)
func2(1,2)
》》》》》》》
func1函数
func1函数的内部函数
3

Process finished with exit code 0

通用的装饰器【当不同被装饰函数的参数不同时,用不定长参数解决】
python函数部分知识

from functools import wraps
def func1(func):
    print("func1函数")
    @wraps(func)
    def inner(*args, **kwargs):
        print("func1函数的内部函数")
        func(*args, **kwargs)
    return inner
@func1
def func2(a,b):
    print(a+b)
def func3(a,b,c):
	print(a*b*c)
func2(1,2)
func3(1,2,3)
>>>>>>>>>>
>func1函数
func1函数的内部函数
3
6

Process finished with exit code 0
(8).带有参数的装饰器

通过装饰器的参数来控制装饰器,例子如下:

#对当前用户增加权限
from functools import wraps
def func1(name=None, level="普通"):
    def outer(func):
        @wraps(func)
        def inner(name):
            print("欢迎,%s"%level)
            func(name)
        return inner
    return outer
@func1(level="大会员")
def func(name):
    print(name)

func("QQ")
》》》》》》》
欢迎,大会员
QQ

Process finished with exit code 0

通过外部参数,返回一个装饰器

3.装饰器与类

装饰器不仅是函数,也可以是类【property】;装饰器不仅可以装饰函数,也可以装饰类

(1).装饰器装饰类

用到单例模式,是面向对象一部分的知识,可以取搜搜看

# cls指的就是类自己
def singleton(cls, *args, **kwargs):
    isinstance={}
    def _singleton():
        if cls not in isinstance:
            isinstance[cls] = cls(*args, **kwargs)
        return isinstance[cls]
    return _singleton
@singleton
class Singleton(object):
    def __init__(self):
        self.num_sum=0
    def add(self):
        self.num_sum=100
(2).将装饰器定义为类

_call_ :魔法方法,可以让类像调用方法一样被调用

import time
class Wrapper():
    def __init__(self, func):
    #实例化对象
        self.func = func
    def __call__(self, *args, **kwargs):
        start = time.time()
        result = self.func(*args, **kwargs)
        end = time.time()
        print(start-end)
        return result
@Wrapper
def func(num):
    time.sleep(3)
    return num
func(1)
》》》》》》》
-3.01536226272583

Process finished with exit code 0
(3).多个装饰器

装饰器生效是从下到上的,也就是离代码越近越先生效

def Dijia(func):
     print("给我力量吧!Dijia")
     def dijia():
         func()
         print("获得dijia的力量!")
     return dijia
def Gaya(func):
    print("给我力量吧gaya!")
    def gaya():
        func()
        print("获得gaya的力量!")
    return gaya

@Dijia
@Gaya
def La():
    print("变身!")
La()
》》》》》》》》》
给我力量吧gaya!
给我力量吧!Dijia
变身!
获得gaya的力量!
获得dijia的力量!

Process finished with exit code 0

4.取消装饰器

wraps不光保留原信息,也保留原形式

from functools import wraps
def light(func):
    print("获得变身棒!")
    @wraps(func)
    def dijia():
        func()
        print("我是迪迦!")
    return dijia
@light
def person():
    print("我是大谷!")
person()

DaGu = person.__wrapped__
print(type(DaGu))
》》》》》》》
获得变身棒!
我是大谷!
我是迪迦!
<class 'function'>

Process finished with exit code 0

文章来源互联网,如有侵权,请联系管理员删除。邮箱:417803890@qq.com / QQ:417803890

微配音

Python Free

邮箱:417803890@qq.com
QQ:417803890

皖ICP备19001818号-4
© 2019 copyright www.pythonf.cn - All rights reserved

微信扫一扫关注公众号:

联系方式

Python Free