DAY11 函数进阶(函数名的本质,闭包,迭代器)
函数名的本质与一级对象:
1.函数名表示函数的内存地址。
2.函数名可以赋值给变量,可以作为容器数据类型的元素。
3.函数名可以作为参数传递给函数。
4.函数名可以作为函数的返回值。
#一。 函数名表示函数的内存地址 def func(): print(111) print(func) >>><function func at 0x00000199DFD22F28> #二。函数名可以赋值给变量,可以作为容器数据类型的元素。 def func(): print(111) f = func #2.函数名可以赋值给一个变量 f() >>> 111 def foo1(): print(1) def foo2(): print(2) def foo3(): print(3) def foo4(): print(4) l1 = [foo1,foo2,foo3,foo4] #3.函数名可以当做容器类数据类型的元素 for i in l1: i() >>> 1 2 3 4 #三。函数名可以作为参数传递给函数 def fun1(): print(222) def func2(x): x() func2(fun1) >>> 222 #四。函数名可以作为函数的返回值 def func1(x): return x def func2(): print('in the func2') res = func1(func2) res()
闭包:
内部函数对外部作用域(非全局作用域)的变量的引用,并返回。该内部函数称为闭包函数。
#这是闭包 def wrapper(x): def inner(): print(x) inner() wrapper('he') >>> 'he' #这是闭包 name = 'he' def wrapper(n): def inner(): print(n) return inner() wrapper(name) ##这不是闭包 name = 'he' def wrapper(): def inner(): print(name) #因为引用了全局作用域的变量 return inner() wrapper()
判断一个内部函数是不是闭包有一个好方法:"__closure__"
(1)如果__closure__有cell为闭包函数
(2)如果__closure__返回的是None,则不是闭包函数。
# 这是闭包,返回有cell就是闭包 def func(): name = 'he' def inner(): print(name) print(inner.__closure__) inner() func() >>> (<cell at 0x00000183451865E8: str object at 0x0000018345217810>,) he #这不是闭包,因为返回的是None name = 'he' def wrapper(): def inner(): print(name) print(inner.__closure__) inner() wrapper() >>> None he
闭包的作用:
# 回顾前面的知识,python解释器遇到一个函数的执行就会开辟一块新的内存空间,然后随着函数的执行结束,这块内存空间会被释放掉。但是如果一个函数被多次调用,就得多次创建内存,然后释放,再创建,再释放。。。这样对内存的损害很大
# 但是,python解释器有一个机制,一旦检测到你的内层是一个闭包,它会在内存中开辟一块新的空间,这个空间不会随着函数的结束而释放。起到了保护内存的作用。
闭包的嵌套:
'''闭包嵌套''' def wrapper(): money = 1000 def func(): name = 'he' def inner(): print(name + ' have ' + str(money)) return inner return func f = wrapper() i = f() i()
可迭代对象(iterable)与可迭代器(iterator)
一. 可迭代对象
前提:在python中,可以理解成一切皆对象。
可迭代对象:(1)对象内部含有"__iter__"方法,就是可迭代对象。
(2)可迭代对象满足可迭代协议。
#回顾我们学过的可迭代对象:str,list,tuple,dict,set,range() # dir(obj) 方法:返回一个对象的所有方法 s1 = 'str' print(dir(s1)) #返回了字符串的所有方法 >>> ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
怎么判断一个对象是否为可迭代对象:
(1)判断方法"__iter__"是否在对象的方法中,因可迭代对象都含有'__iter__'
(2)通过isinstance(obj,type)来判读,返回True/False
from collection import Iterable
isinstance(obj,Iterabel)
# 方法一:通过对象是否含有‘__iter__’方法 dic = {'name':'he','age':23} print('__iter__' in dir(dic)) >>> True # 方法二:通过isinstance()方法判断 from collections import Iterable dic = {'name':'he','age':23} print(isinstance(dic,Iterable)) >>> True
二.迭代器(Iterator)
迭代器:对象内部既含有"__iter__"又含有"__next__"方法的就是迭代器。
判断一个对象是否为迭代器:
(1)这个对象的方法中是否含有'__iter__'和'__next__'
(2)通过isinstace(obj,type)来判断
#我们接触过得迭代器有:文件句柄 # 方法一:判断对象的方法中是否同时含有"__iter__"和"__next__" f = open(r'E:\python_training_s1\day9\register.txt',encoding='utf-8') print('__iter__' in dir(f)) print('__next__' in dir(f)) f.close() >>> True True #方法二:使用isinstance(obj,Iterator),返回True/False from collections import Iterator f = open(r'E:\python_training_s1\day9\register.txt',encoding='utf-8') print(isinstance(f,Iterator)) f.close() >>> True
三.可迭代对象VS迭代器
(1)可迭代对象与迭代器有什么不同?
1.可迭代对象不能取值(之所以能取,是python中作了优化),迭代器能够取值。
2.迭代器非常节省内存,每次只会取一个值,在内存中只占一个内存空间。
3.迭代器是单向的,不能够反复。
(2)可迭代对象转换成迭代器,iterable.__iter__()
l1 = [1,2,3] #可迭代对象 iter_l1 = l1.__iter__() #迭代器 iter(iterable_obj) print(iter_l1,type(iter_l1)) print(iter_l1.__next__()) print(iter_l1.__next__()) print(iter_l1.__next__())
(3)for循环的内部原理
1.将可迭代对象转换为迭代器。
2.调用__next__方法取值
3.利用异常处理停止报错
# 使用while循环重现for循环的原理 s1 = 'abcd' iter1 = s1.__iter__() while 1: try: print(iter1.__next__()) except Exception: break