函数名
函数名就是变量; 函数名可以作为参数进行传递
1. 函数名的内存地址
def func(): print("哈哈") print(func) #<function func at 0x01CDD4B0>
2. 函数名可以赋值给其他变量
def func(): print("呵呵") print(func) a = func #把函数当成变量 赋值给另一个变量 a() # 函数调用 func()
3. 函数名可以作为列表中的元素进行存储
def func1(): print("呵呵") def func2(): print("哈哈") lst = [func1,func2] for el in lst: el()#相当于func1() 和func2()
4.函数名可以当做参数
def func(): print("吃了么") def func2(fn): print("我是func2") fn() #执行传递过来的fn print("我是func2") func2(func) #把函数func当做参数传递给func2的参数fn
运行结果: 我是func2 吃了么 我是func2
5.函数名可以作为函数的返回值
def func1(): print("这里是函数1") def func2(): print("这里是函数2") print("这里是函数1") return func2 fn = func1() #执行完函数1 返回的是函数2 所以fn 就是func2 fn() #func2() 执行结果: 这里是函数1 这里是函数1 这里是函数2
闭包
1. 闭包就是内层函数对外层函数(非全局)的变量的引用
def func1(): name = "alex" def func2(): print(name) func2() func1() 结果是 alex
怎么检测函数是不是闭包?
使用函数名 .__closure__返回cell就是闭包, 返回None就不是闭包
def func1(): name = "alex" def func2(): print(name) # 闭包 alex func2() print(func2.__closure__) #(<cell at 0x013F55D0: str object at 0x01307420>,) func1()
2. 如何在函数外调用函数内部的函数呢?
def outer(): name = "alex" def inner(): print(name) return inner fn = outer() #访问外部函数,获取到内部函数的函数地址 fn() #访问内部函数
3. 如果是多层嵌套,只需要一层一层的往外层返回就行了
闭包嵌套
def wrapper(): money = 1000 def func(): name = 'eva' def inner(): print(name,money) return inner return func f = wrapper() #func i = f() #func() i=inner i() #inner()
4. 闭包函数获取网络应用
from urllib.request import urlopen def but(): content = urlopen("http://www.xiaohua100.cn/index.html").read() def get_content(): return content return get_content fn = but() #get_content 返回给but() 所以fn = get_content content = fn() #fn()就是get_content(),执行函数得到 content print(content) content2 = fn() #重新获取内容 print(content2)
迭代器
1. 什么是可迭代对象
字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。
怎么证明呢? 查看一个对象是否是可迭代对象的方法如下
from collections import Iterable #可迭代对象 from collections import Iterator #迭代器 print(isinstance(A,B)) #判断某个对象 A 是不是 B 类型中的实例
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)) print(isinstance(t,Iterable)) print(isinstance(d,Iterable)) print(isinstance(s,Iterable))
2. 什么是可迭代协议
假如我们自己写了一个数据类型,希望这个数据类型里的东西也可以使用for被一个一个的取出来,那我们就必须满足for的要求。这个要求就叫做“协议”。
可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法。
我们可以看一下,列表,元组,字典,集合内部是不是都有一个__iter__的方法
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__的方法
3. __iter__的作用是什么呢?
举个栗子
lst = ["赵四","花生哥", "天台见"] it = lst.__iter__() #获取到迭代器 (可迭代对象.__iter__() 拿到迭代器) print(it.__next__()) #取值 赵四 print(it.__next__()) #取值 花生哥 print(it.__next__()) #取值 天台见 print(it.__next__()) #这一行就超过迭代的元素的个数了 所以会报错StopIeration
这里的__iter__是帮助我们获取到对象的迭代器 it
迭代器中的__next__()用来获取一个迭代器中的元素
可以把要迭代的内容当成子弹,
迭代器__iter__()就是把子弹都装进弹夹中,
发射就是用__next__()把每一个子弹(元素)打出来
也就是说,for循环的时候,一开始是__iter__()来获取迭代器,
后面每次获取元素都是通过__next__()来完成的
迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。
可迭代对象: Iterable, 这里是以lst作为例子, 里面有__iter__()可以获取迭代器,没有__next__()
迭代器: Iterator, 这里是以it作为例子, 里面有__iter__()可以获取迭代器,有__next__()
4. for循环,能遍历一个可迭代对象,他的内部到底进行了什么?
- 将可迭代对象转化成迭代器。(可迭代对象.__iter__())
- 内部使用__next__方法,一个一个取值。
- 加了异常处理功能,取值到底后自动停止。
用while循环模拟for循环:(重点理解一下)
lst = ["张一宁","石可欣","姚明"] it = lst.__iter__() #获取迭代器 while 1: try: #尝试执行 el = it.__next__() #获取下一个元素 print(el) except StopIteration: #错误处理 break
5. 为什么要用for循环呢?
你可能想为什么要用for循环呢? 直接用索引下标就可以取值
lst = [1,2,3,4] index = 0 while index < len(lst): print(lst[index]) index = index + 1
这种方法只适合于有序列的类型,比如:字符串,列表,元组. 但是,对于字典,集合来说就不能用索引来取值了.
所以for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了.
这就是无所不能的for循环,最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存~