Python函数Day3

 

一、函数名的应用

函数名类似于特殊的变量,打印函数名就是打印函数的内存地址

 

① 函数名就是函数的内存地址

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}

 

LEGB

 

 

二、闭包

装饰器的本质就是闭包

面试题:闭包在哪里使用?(爬虫和装饰器会用到闭包)

 

定义:内层函数对外层函数的变量(非全局变量)的引用,并将函数名返回,这样就形成了闭包。

子函数对父级函数的变量进行引用,并且返回函数名,就是闭包。


函数内部定义的函数称为内部函数,内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数

def wraaper():
    name = 'xiaoming'
    def inner():
        print(name)
    inner()
    return inner
wraaper()

# 结果
xiaoming

 

函数名.__closure__  

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 对应取一个值)

④  迭代器单向的,不反复,一条路走到头。next下一个就找不到上一个了,只能全部取完再重新找

 

迭代器的使用:

① 迭代器没索引,为了取值

② 数据量大的时候

 

for 循环机制:

① 将可迭代对象转化为迭代器

② 调用__next__()方法取值

③ 利用异常处理停止报错

 

while 循环模拟for循环的机制

s1 = 'abcdefghijklmn'
iter = s1.__iter__()

while 1:
    try:
        print(iter.__next__())
    except StopIteration:
        break

 

 文件就是迭代器

posted @ 2018-08-17 17:14  st--st  阅读(219)  评论(0编辑  收藏  举报