python之函数闭包、可迭代对象和迭代器

一、函数名的应用

复制代码
# 1,函数名就是函数的内存地址,而函数名()则是运行这个函数。
def func():
    return

print(func)  # 返回一个地址

# 2,函数名可以作为变量。
def func1():
    print(666)

f1 = func1
f2 = f1
f2()  # 就等于func1() 此时执行函数

# 3,函数名可以作为函数的参数。
def func1():
    print(666)

def func2(x):
    x()

func2(func1)  # 输出666 func1作为实参传进func2中,此时在func2中x()等于func1()

# 4,函数名可以当做函数的返回值。
def wraaper():
    def inner():
        print(666)
    return inner

ret = wraaper()  # 执行函数wraaper(),得到返回值inner赋值给ret,这个inner是函数名
ret()  # 输出666,ret()等于inner()
# (注意:这里要调用inner()只能是用ret(),因为inner()是wraaper()的嵌套函数,在全局命名空间中并没有声明,所以直接用inner()不能执行,)

def func2():
    print('in func2')

def func3(x):
    print('in func3')
    return x

f = func3(func2)  # 给func3传进一个参数func2,返回func2赋值给f
f()  # f()等于func2()

# 5,函数名可以作为容器类类型的元素。
def f1():
    print('f1')

def f2():
    print('f2')

def f3():
    print('f3')

l = [f1, f2, f3]
d = {'f1': f1, 'f2': f2, 'f3': f3}
# 调用
l[0]()  # 输出 f1
d['f2']()  # 输出 f2


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()

# 像上面的函数名这种,称为第一类对象。
# 第一类对象(first-class object)指:
# 1.可在运行期创建
# 2.可用作函数参数或返回值
# 3.可存入变量的实体。
# (如果不明白,那就记住一句话,就当普通变量用)
复制代码

 

globals()        locals()
globals()    #返回全局变量(包含内置函数)的一个字典。
locals()      #返回当前位置的变量的字典。
例如:

复制代码
def func1():
    a = 2
    b = 3
    print(globals())  # 此时globals()在局部命名空间中,但也是返回全局命名空间的一个字典
    print(locals())  # 此时locals()在局部命名空间中,所以返回的是局部命名空间的一个字典{'b': 3, 'a': 2}

print(globals())  # 此时globals()在全局命名空间中,返回全局命名空间的一个字典
print(locals())  # 此时locals()在全局命名空间中,所以返回的是全局命名空间的一个字典
func1()

# 结果:

# {'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}

# {'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}

# {'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}

# {'b': 3, 'a': 2}
复制代码

 

总结:
globals()无论在哪个命名空间,返回的都是全局命名空间的一个字典
locals()在哪个命名空间就返回哪个命名空间的字典

复制代码
def func1():
    a = 2
    b = 3
    def inner():
        c = 5
        d = 6
        print(globals())    #{'__name__': '__main__', '__doc__': None(后面还有一大推东西,省略)...}
        print(locals())      #{'c': 5, 'd': 6}
    inner()
func1()
复制代码

 

二、闭包

1、内层函数引用外层函数的变量(非全局变量),这样该内部函数称就称为闭包函数。

如何创建闭包

  • 闭包函数必须有内嵌函数
  • 内嵌函数需要引用该嵌套函数上一级空间中的变量
复制代码
def wraaper():
    name = '鬼见愁'

    def inner():
        print(name)

    return inner


f = wraaper()
f()


def game(game_name):
    def hero(name):
        print("%s: %s" % (game_name, name))

    return hero


my_game = game("英雄联盟")
my_game("盖伦")
my_game("盲仔")

my_game2 = game("地下城与勇士")
my_game2("剑圣")
复制代码

 

2、判断闭包函数的方法__closure__

复制代码
# 1,是闭包返回值会有cell元素
def wraaper():
    name = '鬼见愁'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner
f = wraaper()
f()


# 2,不是闭包就会返回None
name = '鬼见愁'
def wraaper():
    def inner():
        print(name)
    print(inner.__closure__)  # None
    return inner
f = wraaper()
f()


name = '番薯'
def wraaper(n):
    n = '番薯'
    def inner():
        print(n)
    print(inner.__closure__)  # cell at 0x000002AD93BF76D8
    inner()
    return inner
wraaper(name)
复制代码

 

3、闭包的原理

复制代码
def game(game_name):
    def hero(name):
        print("%s: %s" % (game_name, name))

    return hero


my_game = game("英雄联盟")

print(dir(my_game))
print(my_game.__closure__)
print(type(my_game.__closure__[0]))
print(my_game.__closure__[0].cell_contents)
复制代码

通过__closure__属性看到,它对应了一个tuple,tuple的内部包含了cell类型的对象。

对于这个例子,可以得到cell的值(内容)为"英雄联盟",也就是变量"game_name"的值

原理解释:
当内嵌(hero)函数引用了包含它的函数(game)中的变量(game_name)后,
这个变量会被保存在(hero)的__closure__的cell对象的属性中,成为(hero)本身的一部分;

也就是说,这些变量的生命周期会和(hero)一样。
在上面例子中就是:my_game变量没被销毁,那么game_name("英雄联盟")这个变量会一直存在于my_game变量的属性中

'''
闭包作用:
  当程序执行时,遇到了函数执行,他会在内存中开辟一个空间,局部名称空间,
  如果这个函数内部形成了闭包,
  那么它就不会随着函数的结束而消失。
'''
什么时候用到闭包?
例如:爬虫,装饰器等
下面是一个爬虫的小案例:

复制代码
from urllib.request import urlopen


def index(url):
    def parse(type):
        if type == "GET":
            return urlopen(url).read()
        else:
            return  # 另外的处理,自己写逻辑即可

    return parse


xiaohua = index(url="http://www.xiaohua100.cn/index.html")
get_content = xiaohua("GET")
print(get_content.decode('utf-8'))

post_content = xiaohua("POST")
复制代码

 

三、可迭代对象

可迭代的对象(数据类型)如下: 在python中,但凡带内置有__iter__()方法的数据类型(或者对象),都是可迭代的对象

            1.列表类型  

            2.元组类型 

            3.集合类型  

            4.字典类型  

            5.文本类型(文本类型本身就是迭代器对象"具有__next__()"方法)            

不可迭代的对象(数据类型)如下:  

            1.整数类型

            2.浮点数类型

复制代码
for i in 'abc':
    print(i)

for i in 123:
    print(i)  # 'int' object is not iterable,表示不是可迭代对象


# dir():返回一个列表,列表里面包含了传入的参数的属性、方法
dir('abc')  # ['__add__', '__class__', '__contains__', '__iter__', __str__'  ...]
复制代码

 

判断一个对象是否是可迭代对象:

复制代码
# 第一个方法
s1 = 'abc'
dic = {'name':'xiaoming'}
print('__iter__' in dir(s1))
print('__iter__' in dir(dic))


# 第二种方法
from collections import Iterable  # 判断是否为可迭代对象
from collections import Iterator  # 判断是否为迭代器

print(isinstance('xiaoming',Iterable))  # True
print(isinstance('xiaoming',Iterator))  # False

print(isinstance('xiaoming',str)) # True
#isinstance() 应用比type()更广泛,isinstance()不仅可以判断你是不是可迭代对象,
#也可判断你是否迭代器,还可以判断你是什么类型的数据等等,而#type()只能判断你是什么数据类型
复制代码

 

四、迭代器

1、对象内部含有__iter__方法且含有__next__方法就是迭代器

#文件句柄是迭代器:
f = open('register', encoding='utf-8')
print('__iter__' in dir(f))      #True
print('__next__' in dir(f))      #True

#字典是可迭代对象,不是迭代器。
print('__iter__' in dir(dict))   #True
print('__next__' in dir(dict))   #False


2、可迭代对象与迭代器的区别:

  1. 可迭代对象的取值依赖索引
  2. 迭代器提供了一种不依赖索引取值的方式
  3. 迭代器非常节省内存
  4. 迭代器每次只会取一个值
  5. 迭代器单向的,一条路走到头
  6. 迭代器一定是可迭代对象,反之却不一定


3、可迭代对象如何转化成迭代器

可以使用函数 iter() 或者 __iter__() 获取相应的迭代器

lis = [1, 2, 3]  # 可迭代对象
ite1 = lis.__iter__()  # 迭代器  <list_iterator object at 0x0000027A183BFFD0>
ite1 = iter(lis)  # 迭代器  <list_iterator object at 0x0000027A183BFFD0>
print(ite1)

 

4、迭代器如何取值?

使用next() 或者 __next__() ,每使用一次next 取一个值

print(ite1.__next__())
print(ite1.__next__())
print(next(ite1))

 

5、while循环模拟for循环机制
1,将可迭代对象转化成迭代器。
2,调用__next__方法取值。
3,利用异常处理停止报错。

s1 = 'abcdefg'
iter1 = s1.__iter__()
while 1:
    try:
        print(iter1.__next__())
    except StopIteration:
        break

 

posted @   我用python写Bug  阅读(351)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示