闭包、装饰器、迭代器、生成器

一、闭包:
1,闭包存在于函数中。
2,闭包就是内层函数对外层函数(非全局变量)的引用。
3,最内层函数名会被逐层的返回直至返回给最外层。

def func():
    name = 'alex'
    def inner():
        print(name)
    return inner	
ret = func()  # inner
# ret()
print(ret.__closure__)  # 只要返回cell 它就是闭包
print(ret.__closure__[0])# 只要返回cell 它就是闭包
print(ret.__closure__[0].cell_contents)  # 只要返回cell 它就是闭包


name = 'barry'
def func():
    def inner():
        print(name)
    return inner
ret = func()  # inner
# ret()
print(ret.__closure__)  # 只要返回None它就不是闭包


#不是闭包
name = 1
def func():
    print(name)
func()


#是闭包 n1虽然是外部全局变量,但当时传参数时  name = n1 ,那就是相当于外层函数有个name的变量
def func(name):
    def inner():
        print(name)
    return inner
n1 = 'barry'
ret = func(n1)  # inner
print(ret.__closure__)

  

# 闭包的作用是什么?

def func(step):
    num = 1
    num += step
    print(num)

for i in range(5):
    func(2)

# 闭包的作用:解释器遇到闭包,会触发一个机制,这个闭包不会随着它的结束而释放。
def func(step):
    num = 1
    def inner():
        nonlocal num
        num += step
        print(num)
    return inner

f = func(2)
for i in range(5):
    f()
f()
f()

  


闭包的应用(网页爬取)

from urllib.request import urlopen
def func():
    content = urlopen("http://www.cnblogs.com/jin-xin/articles/8259929.html").read()
    return content

#print(func())
print(func().decode('utf-8'))


from urllib.request import urlopen
def but(a):
    content = urlopen(a).read()
    def get_content():
        return content
    return get_content
fn = but('http://www.cnblogs.com/jin-xin/articles/8259929.html')
#fn = but('http://www.cnblogs.com/jin-xin/articles/8254334.html')
con = fn()   # 获取内容 
print(con.decode('utf-8'))
print(con.decode('utf-8'))
print(con.decode('utf-8'))
print(con.decode('utf-8'))   #中文显示
content2 = fn()  # 重新获取内容
print(content2.decode('utf-8'))

  

二、装饰器
其实装饰器本质是闭包,在不改变原函数的调用指令情况下,给原函数增加额外的功能。它的传参,返回值都是借助内层函数inner,
它之所以借助内层函数inner 就是为了让被装饰函数 在装饰器装饰前后,没有任何区别,看起来没有变化。

进化序列:

# 第一版:写一个功能测试其他同事的函数的执行效率
import time

def func():
    time.sleep(0.2)
    print('非常复杂')

def func1():
    time.sleep(0.3)
    print('超级复杂')

start_time = time.time()
func()
end_time = time.time()
print('此函数的执行效率为%s' % (end_time - start_time))


# 第二版:
import time

def func():
    time.sleep(0.2)
    print('非常复杂')

def func1():
    time.sleep(0.3)
    print('超级复杂')

def timmer(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print('此函数的执行效率为%s' % (end_time - start_time))

timmer(func)
timmer(func1)
# func()
# 如果在实际项目中测试函数,
# 假如函数有1500个,那么你1500个timmer(func),工作量很大。
# 你要在不改变函数执行的指令下,同时测试效率。



# 第三版:在不改变函数的执行方式下,同时测试执行效率。
# 装饰器的雏形
import time

def func():
    time.sleep(0.2)
    print('非常复杂')

def func1():
    time.sleep(0.3)
    print('超级复杂')

def timmer(f):
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
    return inner

func = timmer(func)
# 语法糖 @
func()
func1 = timmer(func1)
func1()



# 装饰器的雏形的优化
# timmer 就是装饰器: 在不改变原函数的调用指令情况下,给原函数增加额外的功能。
import time

def timmer(f):
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
    return inner

@timmer # func = timmer(func)
def func():
    time.sleep(0.2)
    print('非常复杂')

@timmer # func1 = timmer(func1)
def func1():
    time.sleep(0.3)
    print('超级复杂')

func()
func1()

# 被装饰函数带参数
import time

def timmer(f):
    def inner(*args,**kwargs):  # 函数的定义: * 聚合。args = (1,2,3,434545,4234.)
        # a1 = 'wusir'
        # b1 = 'alex'
        start_time = time.time()
        f(*args,**kwargs)  # 函数执行:* 打散。f(*(1,2,3,434545,4234.),)
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
    return inner

@timmer # func = timmer(func)
def func(a,b):
    time.sleep(0.2)
    print('非常复杂%s%s'% (a,b))
func('wusir','alex')  # inner()

@timmer # func = timmer(func)
def func(a,b,c):
    time.sleep(0.2)
    print('非常复杂%s%s%s'% (a,b,c))
func('wusir','alex','barry')  # inner()

# 被装饰的函数要有返回值
import time

def timmer(f):  # f = func
    def inner(*args,**kwargs):
        start_time = time.time()
        ret = f(*args,**kwargs)  # func()
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
        return ret
    return inner

@timmer # func = timmer(func)
def func(a,b):
    time.sleep(0.2)
    print('非常复杂%s%s'% (a,b))
    return 666
ret = func('wusir','alex')  # inner()
print(ret)

@timmer # func = timmer(func)
def func(a,b,c):
    time.sleep(0.2)
    print('非常复杂%s%s%s'% (a,b,c))
func('wusir','alex','barry')  # inner()


# 装饰器的应用
flag = False

def login():
    username = input('用户名')
    password = input('密码')
    if username == 'alex' and password == '123':
        print('登陆成功')
        global flag
        flag = True

def auth(f): # f = func3函数名
    def inner(*args,**kwargs):
        while 1:
            if flag:
                ret = f(*args,**kwargs)
                return ret
            else:
                login()
    return inner

@auth
def comment():
    print('欢迎来到评论页面')

@auth
def artcle():
    print('欢迎来到文章页面')

@auth
def dairy():
    print('欢迎来到日记页面')

comment()
artcle()
dairy()

dic = {
    1: artcle,
    2:dairy,
    3:comment,
}

三、迭代器


可迭代对象:这个对象由多个元素组成,它就是可迭代的。
这个对象内部只要含有"__iter__"方法,它就是可迭代的。
遵循可迭代协议。可迭代对象不一定是迭代器,但迭代器一定是可迭代对象。

# int str bool list tuple dict set bytes range 文件句柄
不可以迭代对象:int bool
可以迭代对象:str list tuple dict set bytes range 文件句柄

判断一个对象是否是可迭代的 --> 是否含有"__iter__"方法
s1 = 'alex'
print(dir(s1))
i = 100
print(dir(i))
print('__iter__' in dir(range))
方法一:内部含有__iter__方法并且含有__next__方法的就是迭代器。
l1 = [1,2,3]
print('__iter__' in dir(l1)) #True
print('__next__' in dir(l1)) #False




方法二:判断一个对象是否是迭代器,可迭代对象的另一种方式:

from collections.abc import Iterator
from collections.abc import Iterable
#from collections import Iterator #DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
#from collections import Iterable #DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working

#列表
l1 = [1,2,3,4]
print(isinstance(l1,Iterator)) #False
print(isinstance(l1,Iterable)) #True

# 文件句柄?
with open('test.py',encoding='utf-8') as f1:
    print(isinstance(f1,Iterator)) #True

#可迭代对象不能直接取值,必须转化成迭代器进行取值。
eg:
l1 = [1,2,3] # 将一个可迭代对象 转化成迭代器
for i in l1:
  print(i)

l1 = [1, 2, 3] # 将一个可迭代对象 转化成迭代器
obj1 = iter(l1)
print(obj1)       #<list_iterator object at 0x000001E7EB8A2CF8>
print(next(obj1)) # 一个next对应一个值
print(next(obj1))
print(next(obj1))
判断一个对象是否是迭代器
# while 模拟for循环循环可迭代对象的机制。
# 1,将可迭代对象转化成迭代器。
# 2,利用next进行取值。
# 3,利用异常处理停止循环。
l1 = [1, 2, 2, 3, 4, 4, 5, 5]
# obj = l1.__iter__()
obj = iter(l1)
while 1:
    try:
        print(next(obj))
    except StopIteration:
        break

迭代器有什么作用?
1,节省内存。
2,一条路走到底,不反复。
3,不易看出。

  

  

四、生成器

生成器:本质就是迭代器,自己可以通过代码写出来的迭代器。
生成器的生成方式:1.函数式生成器。2.生成器表达式。

1、函数中只要有yield 它就不是函数了,它是生成器函数
yield 与 return的区别:
return直接终止函数,yield不会终止函数。
return给函数的执行者返回值,yield是给next(生成器对象)返回值。

def func():
    yield 5
    yield 6
    yield 7
    yield 8
g = func() # 生成器对象
print(g)
# 一个next对应一个 yield
print(next(g))
print(next(g))
print(next(g))
print(next(g))



def book():
    for i in range(1,501):
        print('python全栈开发  编号%s' %i)

def book_niu():
    for i in range(1,501):
        yield 'python全栈开发  编号%s' %i

book()
gen = book_niu()
for i in range(50):
    print(next(gen))
for i in range(30):
    print(next(gen))


send方法
send 与 next的区别 send不仅可以取值,还可以给上一个yield发送一个值
第一个send不可以传值只能传None,因为上面无yield可传,最后一个yield 永远不会收到send发送的值

def func():
    a = 1
    b = 2
    c = 3
    count = yield a + b + c
    print(count)
    yield 6
    yield 7
    yield 8
g = func()
print(next(g))
print(g.send('barry'))  send不仅可以取值,还可以给上一个yield(例如:yield a + b + c)发送一个值
print(g.send(None))
print(g.send(None))

  

yield from方法

def func():
    l1 = ['barry', 'alex', 'wusir', '日天']
    # yield l1
    yield from l1  # 将一个可迭代对象转化成了生成器返回
g = func()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# print(next(g))
for i in g:
    print(i)

  



2、生成器表达式与列表推导式 生成器表达式与列表推导式非常类似,容易着魔

 列表推导式:构建一个列表
# [100以内所有的偶数],[0,2,4,6,8....100]

l1 = []
for i in range(0,101,2):
    l1.append(i)
print(l1)
# 列表推导式分为两种模式:
# 用一行代码构建一个列表,列表推导式只能构建简单的或者比较复杂的列表。
# 1,循环模式。 [变量(加工后的变量) for 变量 in iterable]
print([i for i in range(0,101,2)])
[1,4,9,16,25,36,49]
print([i*i for i in range(1,8)])
# ['python1期', 'python2期', .....'python20期']
print(['python%s期'%i for i in range(1,21)])

# 2,筛选模式
# [变量(加工后的变量) for 变量 in iterable if 条件]
print([i for i in range(1,31) if i % 3 == 0])
# 30以内能被2整除的数的平方
print([ i*i for i in range(1,31) if i % 2 == 0])
# [1,2,3,4,6,7,8]
print([i for i in range(1,9)if i != 5])
l1 = ['wusir','ba', 'aa' ,'alex']
# 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
print([i.upper() for i in l1 if len(i) > 3])
['WUSIR','ALEX']
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# 将列表中的至少含有两个'e'的人名留下来。
# l1 = []
# for l in names:
#     for name in l:
#         if name.count('e') >= 2:
#             l1.append(name)
# print(l1)
print([name for l in names for name in l if name.count('e') >= 2])

  

  


生成器表达式:生成器表达式和列表推导式的语法上一模一样,只是把[]换成()就行了。比如将十以内所有数的平方放到一个生成器表达式中

生成器表达式和列表推导式的区别:

列表推导式比较耗内存,所有数据一次性加载到内存。而.生成器表达式遵循迭代器协议,逐个产生元素。
得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器
列表推导式一目了然,生成器表达式只是一个内存地址。 无论是生成器表达式,还是列表推导式,他只是Python给你提供了一个相对简单的构造方式,因为使用推导式非常简单,所以大多数都会为之着迷,这个一定要深重,推导式只能构建相对复杂的并且有规律的对象,对于没有什么规律,而且嵌套层数比较多(for循环超过三层)这样就不建议大家用推导式构建。
生成器的惰性机制: 生成器只有在访问的时候才取值,说白了.你找他要才给你值.不找他要.他是不会执行的.

# print((i for i in range(1,31) if i % 3 == 0))
gen = (i for i in range(1,31) if i % 3 == 0)
for i in gen:
    print(i)

  

# 匿名函数: 一句话函数
# def func(a,b):
#     return a + b
# print(func(1,3))
# func1 = lambda x,y: x + y
# # print(func1(1,3))
# print(func1)
# 将 x, y 较大者返回
# func2 = lambda x,y: x if x > y else y
# print(func2(100,200))


# eval 慎用
# print('1 + 2')
# print(eval('1 + 2'))

# n=81
# print(eval("n + 4"))  # 85
#
# exec
# s1 = '''
# for i in range(4):
#     print(i)
# '''
# exec(s1)

#
# print(1,2,3,sep='|')  # 分隔符
# print(1,2,3,end=' ')  # 换行符
# f = open('log','w',encoding='utf-8')
# print('写入文件',file=f,flush=True)
# print(help(str))

# def func():
#     pass
# ret = 888
# # print(callable(func))
# print(callable(ret))

# print(float(100),type(float(100)))
# print(bin(100))
# print(abs(-100))
#
# ret = divmod(10,3)
# print(ret)  # (商,余数)


# sum  ***
# print(sum([i for i in range(101)]))
# print(sum([i for i in range(101)],100))

# min 可以加key=函数  ***
# max    ***
# l1 = [3,4,1,2,7,-5]
# print(min(l1))
l1 = [('a',3),('b',2),('c',1)]
# def func(x):
#     '''
#     x = (c,1)   1
#     '''
#     return x[1]
# 改成lambda
# func = lambda x : x[1]
# # # print(lambda x : x[1])
# # # print(func)
# # print(min(l1,key=lambda x : x[1]))

#
# l1 = [i for i in range(10)]
# # print(l1)
# # print(reversed(l1))   ***
# for i in reversed(l1):
#     print(i)
s = 'alex'
# b = s.encode('utf-8')
# s1 = b.decode('utf-8')

# b = s.encode('utf-8')
# print(b)
# bs = bytes(s,encoding='utf-8')
# print(bs)
# print(chr(97))
# print(chr(65))

# repr
# s1 = 'alex'
# # print(s1)
# # print(repr(s1))
# s2 = '我叫%s'%('barry')
# s2 = '我叫%r'%('barry')
# print(s2)

# sorted ***
# l1 = [1,2,8,7,5]
# print(min(l1))

# l1 = [('c',2),('b',3),('a',1)]
# # print(sorted(l1))
# print(sorted(l1,key=lambda x:x[1]))

# print(all([1,2,[1,2,3],'alex',True]))
# print(any([1,'',[],(),False]))
# zip 拉链方法  ***
# l1 = [1,2,3,4]
# tu1 = ('a','b','c')
# tu2 = ('a1','b1','c1')
# g = zip(l1,tu1,tu2)
# # print(list(g))
# for i in g:
#     print(i)
l1 = [1,2,3,4,5,6,7]
# print([i for i in l1 if i > 3])
# ret = filter(lambda x:x>3,l1)
# # # print(ret)
# # # print(list(ret))
# [1,4,9,16,25]
# map
# print([i**2 for i in range(1,6)])
# ret = map(lambda x:x*x,range(1,6))
# print(list(ret))

from functools import reduce

# def func(x,y):
#     return x + y  # 3
ret = reduce(lambda x,y: x + y,[1,2,3,4,5])
print(ret)
匿名函数 和 一些内置函数 
# -*- coding: utf-8 -*-
# @Time    : 2019/1/27 9:42
# @Author  : 景丽洋
# @Email   : xxx@admin.com
# @File    : 3.内容回顾.py
# @Software: PyCharm
 
# 函数进阶
# 装饰器
    # 在不改变函数原本调用方式的基础上添加一些功能
    # @装饰器名
    # 如何写一个装饰器
    # 计算函数执行时间
    # 用户认证
    # 给函数添加日志
# def wrapper(func):
#     def inner(*args,**kwargs):
#         '''在被装饰的函数之前添加功能'''
#         ret = func(*args,**kwargs)
#         '''在被装饰的函数之后添加功能'''
#         return ret
#     return inner
#
# @wrapper    # func = wrapper(func)
# def func():
#     pass
# def wrapper2(func):
#     def inner(*args,**kwargs):
#         print('wrapper2 before')
#         ret = func(*args,**kwargs)
#         print('wrapper2 after')
#         return ret
#     return inner
#
# def wrapper1(func):
#     def inner(*args,**kwargs):
#         print('wrapper1 before')
#         ret = func(*args,**kwargs)
#         print('wrapper1 after')
#         return ret
#     return inner
#
# @wrapper2
# @wrapper1    # func = wrapper(func)
# def func():
#     print('in func')
# func()
 
# 登陆 -- 装饰器 auth
# 计算函数的执行时间 -- 装饰器 timmer
# @auth
# @timmer
# def func():
#     pass
 
# flag = False
# def outer(flag):
#     def timmer(func):
#         def inner(*args,**kwargs):
#             if flag:
#                 print('wrapper1 before')
#                 ret = func(*args,**kwargs)
#                 print('wrapper1 after')
#             else:
#                 ret = func(*args, **kwargs)
#             return ret
#         return inner
#     return timmer
#
# @outer(flag)   #outer(flag) =  timmer    @outer(flag) =  @timmer
# def func():
#     print('in func')
#
# func()
 
 
# 迭代器和生成器
# 可迭代对象
# 可迭代对象可以通过for/iter方法将一个可迭代对象转换成一个迭代器  ,list str range
# 迭代器
# 使用迭代器 : 节省内存,迭代器一项一项的取,节省内存 文件句柄
# 生成器
    # 我们自己写的迭代器
    # 生成器的本质就是迭代器,所有的生成器都是迭代器
# 实现生成器的方法 :
    # 生成器函数 :一定带yield关键字
    # g = func()
    # 生成器表达式 : 用小括号表示的推导式
# 生成器的特点:
    # 1.可以用next/send方法从中取值
    # 2.生成器中的数据只能从头到尾取一次
    # 3.惰性运算 :不取生成器是不工作的
 
# def demo():
#     for i in range(4):
#         yield i
# g=demo()
#
# g2=(i for i in g)
# g1=(i for i in g)
#
# print(list(g1))  # 0,1,2,3   # 这一步才开始从g1中取值
# print(list(g2))  #
 
# 列表推导式(排序)
    # [i**2 for i in lst]
    # [i**2 for i in lst if i%2 ==0 ]
# 生成器表达式
    # (i**2 for i in lst)
 
# 匿名函数
    # lambda 参数1,参数2,参数3 : 返回值/返回值相关的表达式
 
# 内置函数
    # min max map filter sorted   单记
    # reduce --> functool
    # zip sum enumerate
景丽洋的复习笔记

  

原文地址:https://www.cnblogs.com/linux985/p/10332664.html