回顾一下
函数名的本质就是函数的内存地址
1可以被引用
2可以当做容器类性的元素
3可以当做函数的参数和返回值
一、闭包
闭包的含义:内部函数引用外部作用域(非全局)的变量 (内部函数指的是函数内部定义的函数)
有与有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们有需求就是想拿到那怎么做呢?返回呀!
我们都知道函数内的变量我们想要在函数外不用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数名字返回就好了呢?
这才是闭包函数最常用的方法
def func(): name = 'eva' def inner(): print(name) return inner f = func() f()
判断闭包的方法__closure__
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f()
#输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
闭包嵌套
def wrapper(): money = 1000 def func(): name = 'eva' def inner(): print(name,money) return inner return func f = wrapper() i = f() i()
爬虫里的闭包
from urllib.request import urlopen def index(): url = "https://www.cnblogs.com/gzying-01/" def get(): return urlopen(url).read() return get xiaohua = index() content = xiaohua() print(content.decode('utf-8')) # 解码中文显示
二、迭代器
1、首先什么是可迭代对象?
字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。
那我们如何来证明呢?上代码:
from collections import Iterable l = [1,2,3,4] t = (1,2,3,4) d = {1:2,3:4} s = {1,2,3,4} print(isinstance(l,Iterable)) # 返回bool值 print(isinstance(t,Iterable)) print(isinstance(d,Iterable)) print(isinstance(s,Iterable))
#返回结果
True
True
True
True
2、可迭代协议
我们现在是从结果分析原因,能被for循环的就是“可迭代的”,但是for怎么知道谁是可迭代的?
假如我们自己写了一个数据类型,希望这个数据类型里的东西可以被使用for循环一个个取出来,那我们就必须满足for的要求。这个要求就叫做“协议”。
可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__inter__方法
print(dir([1,2])) print(dir((2,3))) print(dir({1:2})) print(dir({1,2})) 结果: ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index'] ['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'] ['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update'] 验证结果
总结一下现在我们所知道的:可以被for循环的都是可迭代的,要想可迭代,内部必须有一个__iter__方法。
接着分析,__iter__方法做了啥事儿?
可迭代的:内部必须含有一个__iter__方法。
3、迭代器
什么叫做迭代器?迭代器英文叫做iterator。
l = [1,2,3,4] l_iter = l.__iter__() # 将可迭代的转化成迭代器 item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item)
迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。
for循环,能遍历一个可迭代对象,他的内部到底进行了什么?
将可迭代对象转化成迭代器。(可迭代对象.__iter__())
内部使用了__next__方法,一个一个取值。
交了 异常处理功能,取值到底自动停止。
用为了循环模拟for循环:
l = [1,2,3,4] l_iter = l.__iter__() while True: try: item = l_iter.__next__() print(item) except StopIteration: break
4、为什么要有for循环?
给予上面的一大堆遍历方法,貌似看上去就可以满足我们的遍历需求了,为何还要搞一个叫做for的玩意儿?
=[1,2,3] index=0 while index < len(l): print(l[index]) index+=1 #要毛线for循环,要毛线可迭代,要毛线迭代器
没错,序列类型字符串,列表,元组都有下标,用上述方法遍历,确实看上去很完美。但是如果遇到非序列类型的比如字典,集合,文件句柄这些家伙,是不是就不灵了。所以,for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了,而且你看到的效果也确实如此,这就是无所不能的for循环,最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存~