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

 

  

 

 

 

 

  

 

posted @ 2018-08-17 15:41  hehehe1994  阅读(107)  评论(0编辑  收藏  举报