函数名的本质
1 函数名就是内存地址
1 def func(): 2 print(666) 3 print(func) # <function func at 0x0000024E020AB950>
2 函数名可以作为变量
首先,我们先对一个变量进行赋值操作,最终得到c的结果
1 a = 2 2 b = a 3 c = b 4 print(c) # 2
同样,对函数名进行赋值操作,看能得到什么结果?
1 def func1(): 2 print(666) 3 f1 = func1 4 f2 = f1 5 print(f1) # <function func1 at 0x00000253AA14B950> 6 f1() # 666 7 f2() # 666
从上面的结果可知,f1,f2得到的是函数函数名,打印出来的是函数名的地址,而f1(),f2()是函数的内容,也就是函数func1()
3 函数名可以作为函数的参数
1 def func(): 2 print(666) 3 def func1(): 4 func() 5 def func2(x): 6 x() 7 func2(func1) # 666
4 函数名可以当作函数的返回值
1 def wraaper(): 2 def inner(): 3 print('inner') 4 return inner 5 ret = wraaper() # 将inner函数的地址赋给wraaper() 6 print(ret) # <function wraaper.<locals>.inner at 0x000002BFFD88B9D8> 7 ret() # inner
1 def func2(): 2 print('in func2') 3 4 def func3(x): 5 print('in func3') 6 return x 7 8 f1 = func3(func2) # in func3 # func2 9 f1() # func2() in func2
4 函数名可以作为容器类类型的元素
def func1(): print('in func1') def func2(): print('in func2') def func3(): print('in func3') def func4(): print('in func4') l1 = [func1, func2, func3, func4] for i in l1: i()
上面介绍的函数,属于第一类对象。
globals() locals()
globals() # 返回全局变量的一个字典
locals() # 返回 当前位置 的局部变量的字典
1 def func1(): 2 a = 2 3 b = 3 4 print(globals()) 5 print(locals()) 6 def inner(): 7 c = 5 8 d = 6 9 print(globals()) 10 print(locals()) 11 inner() 12 print(locals()) 13 print(globals()) 14 func1()
闭包
什么是闭包?内层函数对外层函数的变量(非全局变量)的引用并返回,这样就形成了闭包。
通过下面的例子对比闭包与非闭包的区别:
1 # 闭包 2 def wraaper(): 3 name = 'alex' 4 def inner(): 5 print(name) # alex 6 print(inner.__closure__) # (<cell at 0x0000027D94AFA468: str object at 0x0000027D94B8C148>,) 7 inner() 8 return inner 9 wraaper()
1 # 非闭包 2 name = 'alex' 3 def wraaper(): 4 def inner(): 5 print(name) # alex 6 print(inner.__closure__) # None 7 inner() 8 return inner 9 wraaper()
1 # 闭包 2 name = 'alex' 3 def wraaper(n): 4 n = 'alex' 5 def inner(): 6 print(n) # alex 7 print(inner.__closure__) # (<cell at 0x000001F690D1A468: str object at 0x000001F690DAC180>,) 8 inner() 9 return inner 10 wraaper(name)
闭包的作用:
当程序执行时,遇到了函数执行,他会在内存中开辟一个空间,即局部命名空间,如果这个函数内部形成了闭包,
那么他就不会随着函数的结束而消失。
可迭代对象
什么是可迭代对象?先举一个例子:
1 for i in 'abc': 2 print(i) 3 for i in 123: 4 print(i) # 报错 TypeError: 'int' object is not iterable
从上面可以看出,整数不是可迭代对象。
如何判断对象为可迭代对象?
1. 对象内部含有__iter__方法就是可迭代对象
2. 可迭代对象满足可迭代协议。
就目前所学知识,可迭代对象主要有:str,list,dict,tuple,set,range()。
判断一个对象是否为可迭代对象,通常有两种方法(__iter__,isinstance):
第一种方法:
1 s1 = 'strs' 2 dic = {'name':'alex'} 3 print('__iter__' in dir(s1)) # True 4 print('__iter__' in dir(dic)) # True
第二种方法:
1 1 # 第二种方法: 2 2 s1 = 'strs' 3 3 dic = {'name':'alex'} 4 4 from collections import Iterable 5 5 from collections import Iterator 6 6 print(isinstance('alex',Iterable)) # True 7 7 print(isinstance('alex',Iterator)) # False 8 8 print(isinstance('alex',str)) # True
迭代器
什么是迭代器?迭代器指对象内部含有__iter__方法且含有__next__方法就是迭代器
1 f = open('register', encoding='utf-8') 2 print('__iter__' in dir(f)) 3 print('__next__' in dir(f)) 4 print('__iter__' in dir(dict)) 5 print('__next__' in dir(dict))
可迭代对象与可迭代器的比较。
1. 可迭代对象不能取值,迭代器是可以取值的
2. 可迭代对象 ————>(转化成)迭代器 (__iter__,iter())
1 lis = [1,2,3] # 可迭代对象 2 itel = lis.__iter__() # 将列表转化为迭代器 <list_iterator object at 0x0000012DA426C1D0> 3 print(itel) 4 itel = iter(lis) # # 将列表转化为迭代器 <list_iterator object at 0x000002E0BF96C198> 5 print(itel)
迭代器如何取值? 使用关键字next,每next一次,取一个值。
1 lis = [1,2,3] 2 itel = iter(lis) 3 print(itel.__next__()) 4 print(itel.__next__()) 5 print(itel.__next__()) 6 print(itel.__next__()) # 最后一次报错
从上可以看出,总结迭代器的特点:
1. 可迭代对象不能取值(但可通过切片取值),迭代器是可以取值的,
2. 迭代器非常节省内存,
3. 迭代器每次只会取一个值,
4. 迭代器是单向的,一条路走到头。
for循环的工作原理
1 s1 = 'ndsncla' 2 for i in s1: 3 print(i)
for循环工作机理:
1. 将可迭代对象转化为迭代器
2. 调用__next__方法取值
3. 利用异常处理停止报错
1 s1 = 'ndsncla' 2 s = s1.__iter__() 3 while 1: 4 try: 5 print(s.__next__()) 6 except StopIteration: 7 break