首页 > 技术文章 > 函数名、闭包及迭代器

chris-jia 2018-08-17 15:37 原文

一、函数名的应用及闭包

# 函数名的应用 及闭包
#1, 函数名就是函数对象在内存中的内存地址
def func():
    print(6666)

print(func)   # <function func at 0x000002666B812E18>

#2 函数名,可以作为变量
# a = 2
# b = a
# c = b
# print(b)

def func1():
    print(8888)
f = func1
f2 = f
f()    # 8888

#3,函数名,可以作为函数的参数
def func2():
    print(777,end=" ")
def func3(x):
    print(999,end=" ")
    print(x,end=" ")
    x()
print(func2)   # <function func2 at 0x00000243C9718950>
func3(func2)   #  输出 999  <function func2 at 0x00000243C9718950> 777

#函数名,可以当作函数的返回值
print("\n"+"华丽的分隔线".center(68,'*'))
def wrapper():
    def inner():
        print("in inner")
    return inner
f=wrapper()
f()
# 函数名可以作为容器类型元素
def foo():
    print("I am foo")
def duck():
    print("You are duck")
def beat():
    print("I like this beat")
dic = {'foo':foo,'duck':duck,"beat":beat}
dic['foo']()   # I am foo
dic['duck']()  # You are duck
dic['beat']()  # I like this beat

# 像上面函数名这种,称为第一类对象
# 第一类对象的特点
# 1, 可在运行期创建
# 2,可用作函数参数或返回值
# 3,可存入变量的实体
## 不明白吗?那就记住一句话,就当普通变量用

# 闭包
# 内层函数 对 外层 函数的变量(非全局变量)的引用,这样就形成闭包,内层函数就叫闭包函数
def wrapper():
    name = 'chris'
    def inner():
        print(name)
    return inner
func = wrapper()
func()      # chris

# 判断闭包函数的常用方法:  __closure__
def wrapper():
    name = "LiMing"
    def inner():
        print(name)
    print(inner.__closure__)  # 输出的 __closure__有cell元素:是闭包函数   ,内部函数 被 一层外部函数,闭包
    return inner
wrapper()    #  (<cell at 0x000001FDE53D65B8: str object at 0x000001FDE70485E0>,)


name = 'egg'
def func2():
    def inner():
        print(name)
    print(inner.__closure__)   # 输出的__closure__为None : 不是闭包函数
    return inner
f2 = func2()
f2()   # egg

print("分道线".center(100,'#'))

def wrapper():
    money = 1000
    def func():
        name = 'baby'
        def inner():                             #  内部函数 被 外部两层函数 闭包
            print(name,money)
        print(inner.__closure__)    # (<cell at 0x00000222CAB465B8: int object at 0x00000222CABE6B30>, <cell at 0x00000222CAB46618: str object at 0x00000222CAC086C0>)
        print('inner',inner)       #    inner <function wrapper.<locals>.func.<locals>.inner at 0x00000222CABD8AE8>
        return inner
    return func
f = wrapper()
i = f()
# i()

print("一线天".center(59,'$'))

hobby = 'sing'
def  fn(n):                                    #   n = hobby n 是fn函数的局部变量
    def inner():
        print(n)
        print(n +"1")
    print(inner.__closure__)    # (<cell at 0x000001DFEA006678: str object at 0x000001DFEA0C8768>,)
    return inner
f = fn(hobby)
print(f.__closure__[0].cell_contents)    # 查看闭包的元素
f()                     # sing

'''
闭包的作用:
    当程序执行时,遇到了函数执行,他会在内存中开辟一个空间,局部名称空间,
如果这个函数内部形成了闭我,那么他就不会随着函数的结束而结束。
#闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
#应用领域:延迟计算(原来我们是传参,现在我们是包起来
'''
from urllib.request import urlopen

def index(url):
    def get():
        return urlopen(url).read()
    return get

baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))

 二、迭代器:

 

# 可迭代对象  内部 有 __iter__ 方法

# lis = [1,3,5,10]
#
# print(dir(lis))
# print("__iter__" in dir(lis))


# 什么是迭代器?
# 对象内部含有__iter___方法且含有__next__方法, 就是迭代器

# f = open('register',encoding='utf-8')
# print(f)
# print("__iter__" in dir(f))
# print("__next__" in dir(f))
#
# print("__iter__" in dir(dict))
# print("__next__" in dir(dict))
# print(dir(f))


# 判断一个对象是否可迭代对象:
# 第一个方法
dic = {'name':'chris'}
s1 = "hello world"
print('__iter__' in dir(dic))  # True
print("__iter__" in dir(s1))   # True
# 第二种方法
# from collections import Iterable
# from collections  import Iterator
# print(isinstance(s1,Iterable))  # True  字符串是可迭代对象
# print(isinstance(s1,Iterator))  # False  字符串不是迭代器
# print(isinstance(s1,str))       #  True

# isinstance()方法  vs  type()方法
# isinstance()可以判断对象 ,所从属的所有对象类别 ,而type()方法,仅判断 基本数据类型



#  dir()方法,获取指定对象的所有方法名,将方法名以字符串类型,保存在一个列表中返回。

# 什么是迭代器? 迭代器,从表象上来说,就是具有 __iter__ 和 __next__方法的对象。
# 常见的迭代器,比如说,打开文件时,产生的文件句柄

fhandler = open("register",encoding='utf-8')
print(fhandler)   # <_io.TextIOWrapper name='register' mode='r' encoding='utf-8'>
# 验证 文件句柄 是否具有  __iter__ 和 __next__ 方法
print( "__iter__" in dir(fhandler))    # True
print( "__next__" in dir(fhandler))    # True

# 验证 dict 类型 ,是不是迭代器?
print('__iter__' in dir(dict))        # True    具有这个方法,表示是可迭代对象
print('__next__' in dir(dict))        # False
# 可见 dict 类型,不是迭代器,它仅仅是一个可迭代对象。
# 另外一种判定方法:
from collections import Iterator
print(isinstance(fhandler,Iterator))   # True   是迭代器


# 可迭代对象 vs 迭代器
# 可迭代对象不能取值 ,迭代器是可以取值的。
# 可迭代对象 ---》 (转化成)迭代器
lis = [1,3,5]   # 可迭代对象
ite1 = lis.__iter__()
print(ite1)     # <list_iterator object at 0x00000164B0C784E0>  列表迭代器对象
ite2 = iter(lis)   # <list_iterator object at 0x000001D4D0B451D0>  列表迭代器对象
print(ite2)
# 总结 : 调用可迭代对象的__iter__()方法,或者用iter(iterable)方法,把迭代对象传参进去

# 迭代器如何取值呢? next 一次,取一个值
# print(ite2.__next__())  # 1
# print(ite2.__next__())  # 3
# print(ite2.__next__())  # 5
# print(ite2.__next__())  #  StopIteration   当手动从迭代器,取值,取完了,还取,抛出异常

# 迭代器的特点:
# 1,可迭代对象不能取值,迭代器是可以取值的
# 2, 迭代器非常节省内存
# 3, 迭代器每一次只会取一个值
# 4,迭代器单向的,一条路走到头

# 用 while 循环 模拟 for 循环:
# 1,将可迭代对象转化成迭代器
# 2,调用__next__方法取值
# 3,利用异常处理停止报错
# l = [11,12,13,14,15]
# iter_l = iter(l)
# while 1:
#     try:
#         print(iter_l.__next__())
#     except StopIteration:
#         break

 

推荐阅读