一、函数名(第一类对象)
函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量。
1 def func(): 2 print("呵呵") 3 print(func) 4 结果: 5 <function func at 0x1101e4ea0> #函数名内存地址
1 def func(): 2 print("呵呵") 3 print(func) 4 a = func # 把函数当成一个变量赋值给另一个变量 5 a() # 函数调用 func()
1 #函数名可以当做容器类的元素 2 def func1(): 3 print("呵呵") 4 def func2(): 5 print("呵呵") 6 def func3(): 7 print("呵呵") 8 def func4(): 9 print("呵呵") 10 lst = [func1, func2, func3] 11 for i in lst: 12 i()
1 def func(): 2 print("吃了么") 3 def func2(fn): 4 print("我是func2") 5 fn() # 执⾏传递过来的fn 6 print("我是func2") 7 func2(func) # 把函数func当成参数传递给func2的参数fn.
1 def func_1(): 2 print("这⾥是函数1") 3 def func_2(): 4 print("这⾥是函数2") 5 print("这⾥是函数1") 6 return func_2 7 fn = func_1() # 执⾏函数1. 函数1返回的是函数2, 这时fn指向的就是上⾯函数2 8 fn() # 执⾏上⾯返回的函数
二、闭包
1.闭包是内层函数,对外层函数(非全局)的变量的引用。
1 def func1(): 2 name = "alex" 3 def func2(): 4 print(name) # 闭包 5 func2() 6 func1() 7 结果: 8 alex
2.__closure__来检测函数是否是闭包. 使⽤函数名.__closure__返回cell就是 闭包. 返回None就不是闭包。
1 def func1(): 2 name = "alex" 3 def func2(): 4 print(name) # 闭包 5 func2() 6 print(func2.__closure__) # (<cell at 0x10c2e20a8: str object at0x10c3fc650>,) 8 func1()
3.函数外边调⽤内部函数
1 def outer(): 2 name = "alex" 3 # 内部函数 4 def inner(): 5 print(name) 6 return inner 7 fn = outer() # 访问外部函数, 获取到内部函数的函数地址 8 fn() # 访问内部函数
python规定. 如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡. 将会常驻在内存中. 也就是说. 使⽤闭包, 可以保证外层函数中的变量在内存中常驻.
1 from urllib.request import urlopen 2 def but(): 3 content = urlopen("http://www.xiaohua100.cn/index.html").read() 4 def get_content(): 5 return content 6 return get_content 7 fn = but() # 这个时候就开始加载校花100的内容 8 # 后面需要用到这里面的内容就不需要在执行非常耗时的网络连接操作了 9 content = fn() # 获取内容 10 print(content) 11 content2 = fn() # 重新获取内容 12 print(content2)
综上, 闭包的作⽤就是让⼀个变量能够常驻内存. 供后⾯的程序使⽤.
三、迭代器
可以通过dir函数来查看类中定义好的所有⽅法,可以看到可以进⾏for循环的东⻄都有__iter__函数, 包括range也有。
我们还可以通过isinstence()函数来查 看⼀个对象是什么类型的。
1 l = [1,2,3] 2 l_iter = l.__iter__() 3 from collections import Iterable 4 from collections import Iterator 5 print(isinstance(l,Iterable)) #True 6 print(isinstance(l,Iterator)) #False 7 print(isinstance(l_iter,Iterator)) #True 8 print(isinstance(l_iter,Iterable)) #True
综上. 我们可以确定. 如果对象中有__iter__函数. 那么我们认为这个对象遵守了可迭代协议. 就可以获取到相应的迭代器. 这⾥的__iter__是帮助我们获取到对象的迭代器. 我们使⽤迭代 器中的__next__()来获取到⼀个迭代器中的元素。
1 s = "我爱北京天安门" 2 c = s.__iter__() # 获取迭代器 3 print(c.__next__()) # 使用迭代器进行迭代. 获取一个元素 我 4 print(c.__next__()) # 爱 5 print(c.__next__()) # 北 6 print(c.__next__()) # 京 7 print(c.__next__()) # 天 8 print(c.__next__()) # 安 9 print(c.__next__()) # 门 10 print(c.__next__()) # StopIteration
for循环迭代实质
1 li = [1,2,3,4,5,6,7,8,9,0] 2 it = li.__iter__() 3 while 1: 4 try: 5 print(it.__next__()) 6 except StopIteration: 7 break
总结: Iterable: 可迭代对象. 内部包含__iter__()函数
Iterator: 迭代器. 内部包含__iter__() 同时包含__next__().
迭代器的特点: 1. 节省内存. 2. 惰性机制 3. 不能反复, 只能向下执⾏.
我们可以把要迭代的内容当成⼦弹. 然后呢. 获取到迭代器__iter__(), 就把⼦弹都装在弹夹 中. 然后发射就是__next__()把每⼀个⼦弹(元素)打出来.也就是说, for循环的时候. 开始的时候是__iter__()来获取迭代器. 后⾯每次获取元素都是通过__next__()来完成的. 当程序遇到 StopIteration将 结束循环.