小白跟着大神学Python——Day10 函数的再识2(函数名的运用,闭包函数,迭代器)
一. 函数名的运用
1.函数名是一个特殊的变量。 print(func) #输出一个内存地址,虚拟的。
2.函数名可以当做变量赋值。 def func(): print(666) f1 = func f2 = f1 f3 = f2 print(f3) f3()
3.可以当容器类数据类型的元素。 def func1(): print('in func1') def func2(): print('in func2') def func3(): print('in func3') l1 = [func1, func2, func3] for i in l1: i()
4.函数名可以当做函数的参数。 def func(x): print(x) x() print('in func') def func1(): print('in func1') func(func1)
5.函数名可以当作函数的返回值。 def func(x): # x ---> func1 return x # func1 def func1(): print('in func1') ret = func(func1) # func1 ret() func(func1)()
二. 闭包
闭包函数:
内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数
'''
1,内层函数对外层函数(非全局)变量的引用。
2,闭包只存在于内层函数中。
3,函数都要逐层返回,最终返回给最外层函数。
'''
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!
我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法
def func():
name = 'eva'
def inner():
print(name)
return inner
f = func()
f()
#判断是否是闭包函数的方法:
# print(f.__closure__[index].cell_contents) #只要有值就证明是闭包,None不是闭包。
#闭包的作用:
解释器执行程序时,如果遇到函数,随着函数的结束而关闭临时名称空间,但是!!!如果遇到闭包,有一个机制:那么闭包的空间不会随着函数的结束而关闭。
# 闭包的应用:
1,装饰器。
2,爬虫。
总结:
# 闭包就是在内存中开一个空间,常贮存一些内容,以便后续程序调用。
三. 迭代器
1.1什么是可迭代对象?
字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。
我们怎么来证明这一点呢?
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))
#判断一个对象是否是可迭代对象
#方法一:
print('__iter__' in dir(s)) #True就是可迭代对象
方法二:
print(isinstance(s,Iterable)) #True就是可迭代对象
#缺点:!!!!可迭代对象不能直接取值。
1.2可迭代协议
我们现在是从结果分析原因,能被for循环的就是“可迭代的”,但是如果正着想,for怎么知道谁是可迭代的呢?
假如我们自己写了一个数据类型,希望这个数据类型里的东西也可以使用for被一个一个的取出来,那我们就必须满足for的要求。这个要求就叫做“协议”。
可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法。
1.3迭代器
什么叫做迭代器?迭代器英文意思是iterator。
l = [1,2,3,4] l_iter = l.__iter__() # 将可迭代的转化成迭代器 item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item)
迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。
for循环,能遍历一个可迭代对象,他的内部到底进行了什么?
- 将可迭代对象转化成迭代器。(可迭代对象.__iter__())
- 内部使用__next__方法,一个一个取值。
- 加了异常处理功能,取值到底后自动停止。
用while循环模拟for循环:
l = [1,2,3,4]
l_iter = l.__iter__()
while True:
try:
item = l_iter.__next__()
print(item)
except StopIteration:
break
1.4为什么要有for循环?
基于上面讲的列表这一大堆遍历方式,聪明的你立马看除了端倪,于是你不知死活大声喊道,你这不逗我玩呢么,有了下标的访问方式,我可以这样遍历一个列表啊
=[1,2,3]
index=0
while index < len(l):
print(l[index])
index+=1
#要毛线for循环,要毛线可迭代,要毛线迭代器
没错,序列类型字符串,列表,元组都有下标,你用上述的方式访问,perfect!但是你可曾想过非序列类型像字典,集合,文件对象的感受?
所以嘛,for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法:
即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了;
而且你看到的效果也确实如此,这就是无所不能的for循环,最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存~
总结:
#判断一个对象是否是迭代器:
#方法一:print('__iter__' in dir(obj) and '__next__' in dir(obj)) #方法二: #from collections import Iterable #from collections import Iterator print(isinstance(s1,Iterable))
#type()和isinstance()的区别
#区别:isinstance()不仅可以判断该对象的数据类型,而且可以判断其他很多。 #区别:type()只能判断该对象的数据类型。
#迭代器的作用:
#1.节省内存. #2.惰性机制. #3.一条路走到黑,不走回头路。(也可以调一下指针,但是一般不适用)


浙公网安备 33010602011771号