闭包和迭代器(函数名的应用)
函数名的应用,第一类对象
函数名可以向变量一样进行使用
1.赋值
def func(): print("你吃了么?") print(func) # 打印内存地址 <function func at 0x00000195C2FDD8C8> a = func # 把内存地址赋值给a <function func at 0x00000195C2FDD8C8> = a print(a) a() # 相当于函数的调用
2.作为list元素
def f1(): print("我是马化腾") def f2(): print("我是马云") def f3(): print("我是马赛克") def f4(): print("我是马蓉") lst = [f1, f2, f3, f4] for i in lst: i()
3.作为函数的参数
def func(food): print("吃", food) a = "火锅" func(a) # 调用函数 # =================================== def func(fn): fn() def gn(): print("我是火锅, 刚才有人要吃我") func(gn) # 可以把函数作为参数, 传递给另一个函数
4.作为函数的返回值
def func(): def inner(): print("火锅不让吃了. 吃了上火") return inner # 返回inner内存地址传递给ret ret = func() # 这里func()执行之后获取到的是inner函数 ret() # 这里是让inner函数执行
综上:函数就是一个变量
闭包
内部函数访问外部函数的局部变量
可以使用__closure__来检测函数是否是闭包. 使用函数名.__closure__返回cell就是闭包. 返回None就不是闭包
好处:
1.安全
2.常驻内存,提高效率
def func(): name = "alex" # 常驻内存 防止其他程序改变这个变量 def inner(): print(name) # 在内层函数中调用了外层函数的变量,叫闭包, 可以让一个局部变量常驻内存 return inner ret = func() ret() # 执行的是inner() ret() ret() ret() ret()
# 闭包的好处 from urllib.request import urlopen def but(): content = urlopen("http://www.xiaohua100.cn/daxue/").read() def inner(): print("你好啊") # return content # 在函数内部使用了外部的变量 . 闭包 print(inner.__closure__) # 查看inner是否是闭包, 如果有东西就是闭包, 没东西就不是闭包 return inner print("加载中........") fn = but() # 这个时候就开始加载校花100 的内容 # 后面需要用到这里面的内容就不需要在执行非常耗时的网络连接操作了 content = fn() # 获取内容 print(content) content2 = fn() # 重新获取内容 print(content2)
迭代器
可迭代对象(iterable): 已知的数据类型str.list.tuple.set.句柄.dict
以上的数据内部都包含了 : __iter__(),所有包含了__iter__的数据类型都是可迭代的
dir()来查看一个对象,数据类型中包含了哪些东西
print(dir(str)) print(dir(list)) print(dir(tuple)) print(dir(set)) print(dir(dict)) ...
也可以判断数据类型中是否包含了__iter__
print('__iter__'in dir(str)) print('__iter__'in dir(list)) print('__iter__'in dir(tuple)) print('__iter__'in dir(set)) print('__iter__'in dir(dict)) print('__iter__'in dir(int)) True True True True True False
迭代器(lterator): 内部包含__iter__() __next__()
迭代器的特点:
1.省内存
2.惰性机制
3.只能向前
lst = ["钢铁侠","蜘蛛侠","蝙蝠侠","金刚狼","煎饼侠"] # 获取迭代器 it = lst.__iter__() # 迭代器往外拿元素. __next__() print(it.__next__()) # 钢铁侠 print(it.__next__()) # 蜘蛛侠 print(it.__next__()) # 蝙蝠侠 print(it.__next__()) # 金刚狼 print(it.__next__()) # 煎饼侠 print(it.__next__()) # 迭代到最后一个元素之后. 再进行迭代就报错了
lst = ["钢铁侠","蜘蛛侠","蝙蝠侠","金刚狼","煎饼侠"] # 模拟for循环 it = lst.__iter__() # 获取迭代器 while True: try: # 尝试执行 name = it.__next__() # 获取下一个元素 print(name) except StopIteration: # 处理错误 break
如何判断是否是迭代器
lst = ["钢铁侠","蜘蛛侠","蝙蝠侠","金刚狼","煎饼侠"] from collections import Iterable # 可迭代的 from collections import Iterator # 迭代器 # isinstence(对象, 类型) 判断xx对象是否是xxx类型的 print(isinstance(lst, Iterable)) print(isinstance(lst, Iterator)) # =========================== it = lst.__iter__() # 获取迭代器 print(isinstance(it, Iterable)) # 迭代器一定是可迭代的 print(isinstance(it, Iterator)) # 迭代器里面一定有__next__(), __iter__() # =========================== print("__iter__" in dir(lst)) # 确定是一个可迭代的 print("__next__" in dir(lst)) # 确定不是一个迭代器 # =========================== f = open("今日主要内容",mode="r", encoding="utf-8") print(isinstance(f, Iterable)) print(isinstance(f, Iterator)) True False
======== True True
======== True False
======== True True
总结:
迭代器一定是可迭代的,可迭代的不一定是迭代器
(str.list.tuple.set.文件句柄.dict.....
"文件句柄"是一个迭代器)