一.今日主要内容总览(重点)
1.第一类对象->函数名=>变量名
(1)函数对象可以像变量一样进行赋值
(2)还可以作为列表的元素进行使用
(3)还可以作为返回值返回
(4)还可以作为参数进行传递
思想:函数名就是变量名
(不仅指向一块空间,还有自身的意义)
2.闭包->函数的嵌套
(1)内层函数对外层函数中的变量的使用
(2)好处:
1.保护变量不被侵害
2.让一个变量常驻内存
(3)如何通过代码查看一个闭包?
__closure__: 有东西就是闭包,没东西就不是闭包
(4)迭代器=>固定的思路.for循环
一个数据类型中包含了__iter__函数表示这个数据是可迭代的
dir(数据):返回这个数据可以执行的所有操作
(5) 判断迭代器和可迭代对象的方案(野路子)
__iter__ 可迭代的
__iter__ __next__ 迭代器
(6)判断迭代器和可迭代对象的方案(官方)
from collections import Iterable, Iterator
isinstance(对象, Iterable) 是否是可迭代的
isinstance(对象, Iterator) 是否是迭代器
(7)模拟for循环
lst=[]
#拿迭代器
it=lst.__iter__()
while 1:
try:
it.__next__()
excep StopIteration:
break
#特征:
为了保证安全,我们在内部调用
1. 省内存(生成器)
2. 惰性机制
3. 只能向前. 不能后退
作用:统一了各种数据类型的遍历
3.迭代器->固定的思路.for循环
for循环的底层意义
二.今日内容大纲
1.第一类对象
2.闭包
3.迭代器
三.内容详解
1.第一类对象
(1)
def fn(): print('我叫fn') print(fn)#结果:<function fn at 0x0000025672D298C8>
(2)
def fn(): print('我叫fn') fn() print(fn) gn=fn #函数名可以进行赋值操作 print(gn) gn() ''' 结果: <function fn at 0x00000185567798C8> <function fn at 0x00000185567798C8> '''
(3)
def func1(): print('朱元璋') def func2(): print('朱祁镇') def func3(): print('徐洁') def func4(): print('魏忠贤') #操作一 lst=[func1,func2,func3,func4]#列表中什么都可以放,没有数据类型的限制 print(lst) #结果:朱元璋 #操作二: lst[0]() #操作三: for el in lst: #el是列表中的每一项. el() #拿到函数,执行函数 ''' 结果: 朱元璋 朱祁镇 徐洁 魏忠贤 '''
(4)
def func1(): print('朱元璋') def func2(): print('朱祁镇') def func3(): print('徐阶') def func4(): print('魏忠贤') #操作一 lst=[func1(),func2(),func3(),func4()] print(lst) ''' 结果:#总结:先调用每一个,因为没有返回值,只能是4个None 朱元璋 朱祁镇 徐洁 魏忠贤 [None, None, None, None] '''
(5)
a=10 b=20 c=30 lst=[a,b,c] print(lst) ''' 结果: [10, 20, 30]
(6)
a=10 b=20 c=30 lst=[a,b,c] print(lst) ''' 结果: [10, 20, 30] ''' #通过(4)和(5),发现变量和函数的操作是一样的,变量可能数据类型不同 #函数数据类型相同,变量的每次数据类型不一定相同
(6)#重点降临
def wrapper(): def inner(): print('我的天,还可以这样?') print(inner) #<function wrapper.<locals>.inner at 0x0000021F4F929950> # inner() return inner ret=wrapper() print(ret) #<function wrapper.<locals>.inner at 0x0000021F4F929950>
(6-1)
def wrapper(): def inner(): print('我的天,还可以这样?') print(inner) #<function wrapper.<locals>.inner at 0x0000021F4F929950> # inner() return inner ret=wrapper() print(ret) ##<function wrapper.<locals>.inner at 0x0000021F4F929950> ret() #我的天,还可以这样?
#总结:在函数外部访问了函数内部的函数
''' 结果: <function wrapper.<locals>.inner at 0x000001F1B8609950> <function wrapper.<locals>.inner at 0x000001F1B8609950> 我的天,还可以这样? '''
(7)
def wrapper(): def inner(): print('大冬瓜') return inner #函数名可以向返回值一样返回#返回的是inner,也就是ret ret=wrapper() ret() #在函数外面访问了函数内部的函数 ret() ret()
结果:
大冬瓜
大冬瓜
大冬瓜
(8)
def func1(): print('谢晋') def func2(): print('杨士奇') def func3(): print('徐渭') def func4(): print('柳如是') #代理函数 #代理,也是装饰器的雏形 def proxy(a): #a就是变量,形参 #函数作为参数进行传递 #代理好处,可以加点东西 print('我是代理') a() print('代理执行完毕') proxy(func1) proxy(func3) proxy(func4)
总结:函数名就是变量名
1.函数名可以像变量一样进行传递
2.函数名可以作为参数进行赋值操作
3.可以作为返回值返回
4.可以作为参数进行传递
2.闭包
(1)
def wrapper(): name='周杰伦' def inner(): print(name)#在内层函数中,使用了外层函数的局部变量 inner() wrapper() ''' 结果: 周杰伦 '''
(2)
def wrapper(): name='周杰伦' def inner(): print(name)#在内层函数中,使用了外层函数的局部变量 return inner #返回函数名 ret=wrapper() ret()
对比(1)和(2)的方式
闭包的优点:(定义:内层函数使用了外层函数的变量)
1.可以保护变量不被其他人侵害
2.保持一个变量常驻于内存
(3)#注意下面的注释
def wrapper(): name='周杰伦' def inner(): print(name) #在内层函数中使用了外层函数的局部变量 return inner #返回函数名 ret=wrapper() #ret是一个内层函数 ret() #ret是inner,在外层执行的时机是不确定的,必须保证里面的name必须存在
(4)
#超级简易版爬虫 from urllib.request import urlopen #导入一个模块 def func(): #获取到网页中的内容, content=urlopen('https://www.dytt8.net/').read() return content.decode('gbk') print(func())
(5)#把要反复打开的网站加载 到内存中,以便快速打开网站,缺点:耗内存
#提升缓存能力版
#解决缓存问题 # #超级简易版爬虫 from urllib.request import urlopen #导入一个模块 #苹果系统:干掉数字签名 # import ssl # ssl._create_default_https_context=ssl._create_unverified_context() def func(): #获取到网页中的内容,当网速很慢的时候,反复的去打开这个网站,很慢 content=urlopen('https://www.dytt8.net/').read() def inner(): return content.decode("gbk") #网页内容 return inner # return content.decode('gbk') print('开始网络请求') ret=func() #网络请求已经完毕 print('网络请求完毕') print('第一次',ret()[5]) print('第二次',ret()[5]) # print('第一次',ret()) # print('第二次',ret())
3.迭代器
(1)
s='今天下午考试' for c in s: print(c) #主要讨论:什么是可迭代,什么是不可迭代的?
'''
结果:
今
天
下
午
考
试
'''
(2)
for c in '哼哼哈哈': print(c)#正确 for c in 123: print(c)#错误
(3)
dir() 可以帮助我们查看xxx数据能够执行的操作
print(dir(str)) #__iter__ print(dir(int)) #没有__iter__ print(dir(list)) #有__iter__ print(dir(dict)) #有__iter__ print(dir(bool)) #没有__iter__ for i in True: print(i) #报错:'bool' object is not iterable
(4)
print(dir(range)) f=open('呵呵',mode='r',encoding='utf-8') print(dir(f)) #正确,文件也是可迭代的
共性:所有带有__iter__的东西都可以进行for循环,带有__iter__东西就是可迭代对象
(5)
lst=['贾樟柯','李安','杨德昌','王家卫'] # print('__iter__' in dir(lst)) #判断迭代器是否在lst中,结果:True it=lst.__iter__() #it是拿到的是迭代器 print(it) #列表的迭代地址:<list_iterator object at 0x0000026309647518> print(it.__next__()) #下一个 print(it.__next__()) #下一个 print(it.__next__()) #下一个 print(it.__next__()) #下一个 # print(it.__next__()) #报错:下一个报错,因为列表中只有4个值 StopIteration 停止迭代 it=lst.__iter__() #只能重新获取迭代器 print(it.__next__()) #下一个,又可以用了
总结
1.只能向下执行,不能反复
2.结束的时候会给我们扔来一个错误 StopIteration
3.整合所有的数据类型进行遍历(int,bool除外)#最大的特点
(6)超级重点
lst=['海尔兄弟','阿童木','葫芦娃','舒克贝塔','大风车'] #while循环模拟for循环 for el in lst: it=lst.__iter__() #获取到迭代器0 while 1: #循环 try: #尝试 el=it.__next__() #拿数据 print(el) except StopIteration: #出了错误,意味着数据拿完了 break #结束循环
总结:
1.节省内存
2.惰性机制
3.不能反复,只能向下执行
hello world!
(7)
官方通过代码判断是否是迭代器
借助于两个模块,Iterator迭代器,Iterable可迭代的
from collections import Iterator,Iterable lst=[1,2,3] print(isinstance(lst,Iterator)) #某某某是否是迭代器,False print(isinstance(lst,Iterable)) #某某某是否是可迭代的类型,True it=lst.__iter__() #迭代器一定可迭代,可迭代的东西不一定是迭代器 print(isinstance(it,Iterator)) #某某某是否是迭代器,False print(isinstance(it,Iterable)) #某某某是否是可迭代的类型,True
结果:
False
True
True
True
总结:有些地方还有待完善