一、函数名的应用
函数名类似于特殊的变量,打印函数名就是打印函数的内存地址
① 函数名就是函数的内存地址
def func(): pass >>>func <function func at 0x000001C0BDDAF400>
② 函数名可以作为变量
def func(): print(666) f = func f() # f() == func()
③ 函数名可以作为函数的参数传入
def func1(): print(666) def func2(x): x() # x() == func1() func2(func1)
④ 函数名可以当作函数的返回值
def fun1(): def fun2(): print(666) return fun2 f = fun1() # f = fun2 f() # f() == fun2()
⑤ 函数名可以作为容器类类型的元素
def func1(): print(111) def func2(): print(222) def func3(): print(333) li = [func1,func2,func3] for i in li: i() # func1(),func2(),func3()
Python中一切皆对象,函数名就是第一类对象
global() # 将所有全局变量以字典的形式返回
a = 1 b = 2 c = 3 print(globals()) # 结果 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001F867E586A0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Day11/exercise.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3}
locals() # 将当前作用域(当前位置)的局部变量以字典的形式返回
def func(): a = 1 b = 2 c = 3 print(locals()) >>>func() {'c': 3, 'b': 2, 'a': 1}
二、闭包
装饰器的本质就是闭包
面试题:闭包在哪里使用?(爬虫和装饰器会用到闭包)
定义:内层函数对外层函数的变量(非全局变量)的引用并返回,这样就形成了闭包。
子函数对父级函数的变量进行引用,并且返回函数名,就是闭包。
函数内部定义的函数称为内部函数,内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数
def wraaper(): name = 'xiaoming' def inner(): print(name) inner() return inner wraaper() # 结果 xiaoming
函数名.__closure__ 返回cell地址就是闭包
name = 'xiaoming' def wraaper(args): def inner(): print(args) inner() print(inner.__closure__) return inner wraaper(name) # 结果 xiaoming (<cell at 0x000001CAD4F678B8: str object at 0x000001CAD4E40A30>,)
返回None就不是闭包
name = 'xiaoming' def wraaper(): def inner(): print(name) inner() print(inner.__closure__) return inner wraaper() # 结果 xiaoming None
闭包的作用:
当程序执行时,遇到了函数执行,它会在内存中开辟一个空间,叫局部名称空间,随着函数的结束而消失。
如果这个函数内部形成了闭包,那么它就不会随着函数的结束而消失,在内存中会一直存在。
三、迭代器
可迭代对象:对象内部含有__iter__方法就是可迭代对象
可迭代对象:str(字符串)、list(列表)、dict(字典)、tuple(元组)、set(集合)、range()
可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法。
判断对象是否可迭代对象的方法:
① 判断__iter__是否在对象的方法中,用dir()
dir() 查看对象内的所有属性和方法
s = 'abcde' print('__iter__'in dir(s)) # dir() 查看对象内的所有属性和方法 # 结果 True
② isinstance() 判断是否可迭代对象
iisinstance() 判断是否属于某个已知类型,sinstance() 能判断从属于哪种类型,type()判断哪种基本数据类型
from collections import Iterable li = [1,2,3,4,5] print(isinstance(li,Iterable)) # 判断对象是否可迭代对象
迭代器:对象内部含有__iter__方法且含有__next__方法就是迭代器
判断对象是否迭代器
① 对象是否含有__iter__和__next__方法
li = [1,2,3,4,5] print('__iter__' in dir(li)) print('__next__' in dir(li)) # 结果 True False
② isinstance 判断是否迭代器
from collections import Iterator dic = {'a':1 ,'b':2 ,'c':3} print(isinstance(dic,Iterator)) # 结果 False
可迭代对象是不能取值,迭代器就是通过__next__方法可以一个一个取值。
for循环可迭代对象是for循环内部做了优化才能取值,for含有__next__方法,因为可迭代对象没有__next__方法
四、可迭代对象可以转化为迭代器
转化方法一:__iter__() 方法
from collections import Iterator dic = {'a':1 ,'b':2 ,'c':3} itel = dic.__iter__() # 转化为迭代器 print(itel) # 打印是否迭代器 print(isinstance(itel,Iterator)) # 判断对象是否迭代器 # 结果 <dict_keyiterator object at 0x000002049DC76868> True
转化方法二: iter() 方法
from collections import Iterator li = ['a','b','c',1,2,3] itel = iter(li) # 转化为迭代器 print(itel) # 打印是否迭代器 print(isinstance(itel,Iterator)) # 判断对象是否迭代器 # 结果 <list_iterator object at 0x0000016BEA6F7748> True
五、迭代器的取值
迭代器的取值方式:通过__next__()方法取值,next一次取一个值
Iterator.__next__()
li = ['a','b','c',1,2,3] itel = iter(li) # 转化为迭代器 i = itel.__next__() # 通过__next__()方法取值 print(i) i = itel.__next__() # 通过__next__()方法取值 print(i) # 结果 a b
六、迭代器的好处:
① 可迭代对象不能取值,迭代器是可以取值的
② 迭代器非常节省内存 (__next__()一次就加载一个,加载下一个元素后,上一个元素就会释放掉,跟for的机制相似)
③ 迭代器每次在内存中只会取一个值(一个 next 对应取一个值)
④