python函数名使用及迭代器
函数名可以进行变量赋值
1 def fn():
2 print('我是fn')
3 fn()
4 print(fn)
5 gn = fn
6 gn()
7 print(gn)
8 结果
9 我是fn
10 <function fn at 0x0000027508E81E18>
11 我是fn
12 <function fn at 0x0000027508E81E18>
函数名可以作为列表的元素进行使用
1 def func1():
2 print('我是func1')
3 def func2():
4 print('我是func2')
5 def func3():
6 print('我是func3')
7 lst = [func1,func2,func3]
8 print(lst)
9 lst[0]() #根据列表索引取到函数,执行函数
10 for el in lst:
11 el() #拿到函数,执行函数
12 结果
13 [<function func1 at 0x00000214D5371E18>, <function func2 at 0x00000214D55498C8>, <function func3 at 0x00000214D5549950>]
14 我是func1
15 我是func1
16 我是func2
17 我是func3
函数名可以作为return返回值
1 def wrapper():
2 def inner():
3 print('我是inner')
4 print(inner) #打印函数内存地址
5 inner() #执行inner函数
6 return inner #返回inner函数内存地址
7 ret = wrapper() #ret接收return返回的inner函数内存地址
8 print(ret) #打印赋值给ret接收过来的inner函数内存地址
9 ret() #执行ret函数
10 结果
11 <function wrapper.<locals>.inner at 0x0000014F387998C8>
12 我是inner
13 <function wrapper.<locals>.inner at 0x0000014F387998C8>
14 我是inner
15
16 事例2
17 def wrapper():
18 def inner():
19 print('我是inner')
20 return inner #相当于返回inner函数的内存地址
21 ret = wrapper() #这里接收的是inner内存地址
22 ret() #这里相当于可以多次执行inner函数
23 ret()
24 结果
25 我是inner
26 我是inner
27 对比
28 def wrapper():
29 def inner():
30 print('我是inner')
31 return inner() #如果这里是return inner()相当于在函数内部执行了inner函数
32 ret = wrapper() #这里接收的是return返回值
33 ret #其返函数的回值只能返回一次
34 ret
35 结果
36 我是inner
函数名可以作为参数进行传递
1 def func1():
2 print('我是func1')
3 def func2():
4 print('我是func2')
5 def func3():
6 print('我是func3')
7 def proxy(a): #装饰器的雏形
8 print('test')
9 a()
10 print('执行完毕')
11 proxy(func1)
12 proxy(func2)
13 proxy(func3)
14 结果
15 test
16 我是func1
17 执行完毕
18 test
19 我是func2
20 执行完毕
21 test
22 我是func3
23 执行完毕
总结
第一类对象-> 函数名 -> 变量名
函数对象对象可以像变量一样进行赋值
可以作为列表的元素进行使用
可以作为返回值返回
可以作为参数进行传递
闭包的定义:内部函数使用了外部函数的变量(而非全局变量),外部函数又把内部函数当做返回值返回,内部函数就是一个闭包
闭包使用场景:函数的嵌套
闭包的优点:
1, 可以保护变量不被其他人侵害
2, 保持一个变量常驻内存
1 def wrapper():
2 a = '哈哈' #是一种不安全的写法
3 name = 'jack'
4 def inner():
5 print(name) #在内层函数中使用了外层函数的局部变量
6 print(a)
7 def func():
8 nonlocal a
9 a = 108
10 print(a)
11 return inner #返回inner函数内存地址
12 ret = wrapper()
13 ret()
14 结果
15 jack
16 哈哈
17
18 事例2
19 def wrapper():
20 name = 'jack' #局部变量常驻内存
21 def inner():
22 print(name) #在内层函数中使用了外层函数的局部变量
23 return inner #返回inner函数内存地址
24 ret = wrapper()
25 ret() #ret是内层函数inner
26 结果
27 jack
28
29 事例3
30 def line_config(content,length):
31 def line():
32 print('-'*(length // 2) + content + '-'*(length // 2))
33 return line
34 line1 = line_config('闭包',10)
35 line1()
36 line1()
37 line2 = line_config('闭包',20)
38 line2()
39 结果
40 -----闭包-----
41 -----闭包-----
42 ----------闭包----------
43
44 事例4
45 def test():
46 funcs = []
47 for i in range(1,4):
48 def test2():
49 print(i)
50 funcs.append(test2)
51 return funcs
52 new_func = test()
53 print(new_func)
54 new_func[0]()
55 new_func[1]()
56 new_func[2]()
57 结果
58 [<function test.<locals>.test2 at 0x000001EE87C298C8>,
59 <function test.<locals>.test2 at 0x000001EE87C29950>,
60 <function test.<locals>.test2 at 0x000001EE87C299D8>]
61 3
62 3
63 3
64
65 事例5
66 def test():
67 funcs = []
68 for i in range(1,4):
69 def test2(num):
70 # num = 1
71 def inner():
72 print(num)
73 return inner
74 funcs.append(test2(i))
75 return funcs
76 new_func = test()
77 print(new_func)
78 new_func[0]()
79 new_func[1]()
80 new_func[2]()
81 结果
82 [<function test.<locals>.test2.<locals>.inner at 0x000002BEAA039950>,
83 <function test.<locals>.test2.<locals>.inner at 0x000002BEAA0398C8>,
84 <function test.<locals>.test2.<locals>.inner at 0x000002BEAA0399D8>]
85 1
86 2
87 3
#如果全局没有设置变量a,但函数内部使用了一个global,就等于在全局定义了一个变量a,因为使用了global,所以函数内部修改此变量值,全局生效
1 def func():
2 global a
3 a = 20
4 print(a)
5 func()
6 print(a)
7 结果
8 20
9 20
闭包嵌套
1 def f1(): #1 #3
2 num = 1000 #4
3 def f2(): #5 #9
4 name = 'bob' #10
5 def f3(): #11 #15
6 print(name,num) #16
7 return f3 #12
8 return f2 #6
9 f = f1() #2 #7
10 i = f() #8 #13
11 i() #14 #17
12 结果
13 bob 1000
案例:超级简易版爬虫
1 from urllib.request import urlopen
2 # import ssl
3 # ssl._create_default_https_context = ssl._create_unverified_context()
4 def func():
5 conntent = urlopen('https://www.dytt8.net/').read()
6 def inner():
7 return conntent.decode('gbk')
8 return inner
9 print('开始网络请求')
10 ret = func()
11 print('网络请求完毕')
12 print('第一次',ret()[:5])
13 print('第二次',ret()[:5])
14
15 案例二
16 def index():
17 url = "http://www.baidu.com/index.html"
18 def get():
19 return urlopen(url).read()
20 return get
21 xiaohua = index()
22 content = xiaohua()
23 print(content)
__closure__查看是否是闭包,有内容就是闭包,没有内容就不是闭包
1 def wrapper():
2 name = 'bob'
3 def inner():
4 print('测试')
5 print(inner.__closure__)
6 inner()
7 wrapper()
8 结果
9 None
10 测试
11
12 事例2
13 def wrapper():
14 name = 'bob'
15 def inner():
16 print(name)
17 print('测试')
18 print(inner.__closure__)
19 inner()
20 wrapper()
21 结果
22 (<cell at 0x0000025A45EB75B8: str object at 0x0000025A45F47180>,)
23 bob
24 测试
dir() 可以帮我们查看指定数据能够执行的操作
1 print(dir(str)) # 有__iter__
2 print(dir(int)) # 没有__iter__
3 print(dir(list)) # 有__iter__
4 print(dir(dict)) # 有__iter__
5 print(dir(bool)) # 没有__iter__
6 共性:所有带有__iter__的东西都可以进行for循环,带有__iter__的东西就是可迭代对象
因为数字是不可迭代的,所以for循环报错
1 for i in 123: 2 print(i) 3 结果报错 4 TypeError: 'int' object is not iterable
迭代器
1. 只能向下执行,不能反复
2. 结束的时候会给报一个错误 StopIteration
3. 整合所有的数据类型进行遍历(int,bool除外)
1 lst.__iter__()等于iter()
2 it.__next__()等于next(it)
3
4 lst = ['jary','bob','jack']
5 print('__iter__' in dir(lst)) #判断lst里边中是否带有__iter__方法
6 it = iter(lst)
7 print(it) #返回一个迭代器地址<list_iterator object at 0x000002C5429D7400>
8 print(next(it))
9 print(next(it))
10 print(next(it))
11 print(next(it)) #因为执行到这一行,已经把列表的元素执行完了,取不到元素了就报错
12 结果
13 True
14 <list_iterator object at 0x000002C5429D7400>
15 jary
16 bob
17 jack
18 Traceback (most recent call last):
19 File "E:/Py3Practise/day01/test.py", line 10, in <module>
20 print(next(it))
21 StopIteration
22 如果想重复上次的值,需要重新定义迭代器
用迭代器模拟for循环:for el in lst
1 lst = ['jary','bob','jack']
2 it = iter(lst) #获取到迭代器
3 while 1:
4 try:
5 el = next(it) #拿数据
6 print(el)
7 except StopIteration: #出了错误,意味着数据拿完了
8 break 结束循环
9
10 特征:
11 1. 省内存(生成器)
12 2. 惰性机制
13 3. 只能向前. 不能后退
判断迭代器和可迭代对象的方案
1 __iter__ 可迭代的
2 __iter__ __next__ 迭代器
3
4 官方通过代码判断是否是迭代器
5 借助于两个模块 Iterator迭代器, Iterable可迭代的
6 from collections import Iterable,Iterator
7 lst = [1,2,3]
8 print(isinstance(lst,Iterable)) #lst是否是Iterable(可迭代的)类型的
9 print(isinstance(lst,Iterator)) #lst是否是Iterator(迭代器)类型的
10
11 it = iter(lst) #迭代器一定可迭代,可迭代的不一定是迭代器
12 print(isinstance(it,Iterable)) #it是否是Iterable(可迭代的)类型的
13 print(isinstance(it,Iterator)) #it是否是Iterator(迭代器)类型的
14 for el in it:
15 print(el)
16 结果
17 True
18 False
19 True
20 True
21 1
22 2
迭代器
看下__iter__方法做了什么事情
print([1,2].__iter__())
结果返回
<list_iterator object at 0x000001F7F2F3EA58>
list_iterator(迭代器)
dir([1,2].__iter__()):是列表迭代器中实现的所有方法
dir([1,2]):是列表中实现的所有方法
都是以列表的形式返回给我们的,为了看的更清楚,分别把他们转换成集合,然后取差集
#print(dir([1,2].__iter__()))
#print(dir([1,2]))
print(set(dir([1,2].__iter__()))-set(dir([1,2])))
结果:
{'__next__', '__setstate__', '__length_hint__'}
l = [1,2,3,4]
res1 = l.__iter__()
res2 = l.__iter__()
print(res1)
print(res2)
结果:
<list_iterator object at 0x000002268CEAEAC8>
<list_iterator object at 0x000002268CEAEBA8>
# res1和res2都是迭代器,是两个完全不同的迭代器
__length_hint__迭代器中有多少个元素
l = [1,2,3,4]
res = l.__iter__()
print(res.__length_hint__())
for i in res:
print(i)
控制迭代器从哪儿开始迭代
l = [1,2,3,4]
res = l.__iter__()
res.__setstate__(2)
for i in res:
print(i)
结果:
3
4
事例二
for循环自带报错异常处理
l = [1,2,3]
res1 = l.__iter__()
res2 = l.__iter__()
for i in res1:
print(i)
print('------------')
for i in res1:
print(i)
print('^^^^^^^^^^^^')
结果:
1
2
3
------------
^^^^^^^^^^^^
第一个for把迭代器中的值已经取完了,所以第二个for循环没有值
事例三
for i in l.__iter__():
print(i)
print('**************')
for i in l.__iter__():
print(i)
结果:
1
2
3
**************
1
2
3
因为这两个for循环的迭代器都是现用现定义的,并没有赋值给变量,所以两个迭代器各不影响,都能打印出来值
迭代器 - 概念
可迭代协议 : 内部含有__iter__方法的值/变量都是可迭代的
怎么通过可迭代变成迭代器 : 可迭代变量.__iter__()返回一个迭代器
迭代器协议 : 内部含有__iter__方法和__next__方法的值/变量都是迭代器
迭代器的特点:
具有next和iter方法
通过一个next多次执行就可以获得所有这个容器中的值
迭代器中的值只能取一次
不取的时候值不出现
可迭代和迭代器的关系:
所有的迭代器都是可迭代的,反之不成立
迭代器是特殊的存在
迭代器的作用就是节省内存,for循环就是利用了迭代器节省内存的特点来对python当中的变量来进行操作的
for循环取值
for循环一个列表的时候必须用的__next__取下一个值
for循环内部的机制就是迭代器取值的机制
在for循环执行的过程中 : 先把可迭代的变成一个迭代器,然后再从中一个一个的取值
for循环和迭代器的关系:
无论是可迭代的还是迭代器都可以被for循环
如果直接循环迭代器,那么循环一次就没有了
如果循环的非迭代器,那么每一次循环都相当于从头到尾的循环,是因为在for循环中的所有非迭代器都会通过iter生成一个新的迭代器
print('__next__' in dir(range(6))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__
print('__iter__' in dir(range(6))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__
结果
False
True
from collections import Iterator
print(isinstance(range(100000000),Iterator)) #验证range执行之后得到的结果不是一个迭代器
range生成的就是一个迭代器,创建这个迭代器并不会真的把迭代器中的所有数据一次性生成,只有通过next取值的时候才会生成
记住你要多少个值 ,当前该给你什么,并且记住我下一个该给你什么,下一个和当前这个数的关系
# 创建一个迭代器:每次执行iter方法就创建一个迭代器,每个迭代器都只能取值一次,循环这个迭代器
dic = {'k':'v','k2':'v2'}
dic_iter = dic.__iter__()
print(dic_iter)
结果:
<dict_keyiterator object at 0x000001E3FB0333B8>
print(dic_iter.__next__())
for k in dic_iter:
print(k)
结果:
k
k2
事例二:定义一个计数器来循环
count = 0
l_iter = l.__iter__()
while count < len(l):
print(l_iter.__next__())
count += 1
判断一个变量/值是否是迭代器的方法
lst_iterator = [].__iter__()
print('__iter__' in dir(lst_iterator))
print('__next__' in dir(lst_iterator))
print('__iter__' in dir(lst_iterator) and '__next__' in dir(lst_iterator))
结果:
True
True
True
file文件是一个迭代器还是一个可迭代的?
f = open('file')
print('__iter__' in dir(f) and '__next__' in dir(f)) #表示是一个迭代器,因为既有__iter__方法也有__next__方法
结果:
True
range是一个迭代器还是一个可迭代的?
a = range(10)
print('__iter__' in dir(a)) #可迭代的
print('__iter__' in dir(a) and '__next__' in dir(a)) #可迭代的但是并不是迭代器因为没有__next__方法
结果:
True
False
第二种方法
from collections import Iterator
f = open('file')
print(isinstance(f,Iterator))
print(isinstance(range(10),Iterator))
结果:
True
False
总结
可迭代对象:
拥有__iter__方法
特点:惰性运算
例如:range(),str,list,tuple,dict,set
迭代器Iterator:
拥有__iter__方法和__next__方法
例如:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o

浙公网安备 33010602011771号