python D11 迭代及闭包

# 本节主要内容:
# 1、函数名的使用以及第一类对象
# 2、闭包
# 3、迭代器

# 一、函数名的应用
# 函数名是以个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量。
# 1、函数名的内存地址
# def func():
# print("你是傻子")
# print(func) #<function func at 0x00C0F7C8> 打印出func的内存地址 func带()是执行函数

# 2、函数名可以赋值给变量
# def func():
# print("你是大傻子")
# a = func # 把函数当成⼀个变量赋值给另⼀个变量
# a() # 函数调⽤ func()

# 3、函数名可以当做容器类的元素
# def func1():
# print("呵呵")
# def func2():
# print("呵呵")
# def func3():
# print("呵呵")
# def func4():
# print("呵呵")
# lst = [func1, func2, func3]
# for i in lst:
# i() # 运行列表中所有函数

# 4、函数名可以当做函数的参数
# def func():
# print("吃了么")
# def func2(fn):
# print("我是func2")
# fn() # 执⾏传递过来的fn
# print("我是func2")
# func2(func) # 把函数func当成参数传递给func2的参数fn

# 5、函数名可以作为函数的返回值
# def func_1():
# print("这⾥是函数1")
# def func_2():
# print("这⾥是函数2")
# print("这⾥是函数1")
# return func_2

# fn = func_1() # 执⾏函数1. 函数1返回的是函数2, 这时fn指向的就是上⾯函数2
# print(fn) # <function func_1.<locals>.func_2 at 0x009C57C8> 返回的是func2的内存地址
# fn() # 执⾏上⾯返回的函数

# 6、把函数名当变量来使用
# 代理模式、装饰器的雏形
# def func(fn): #fn 可以代理func1/func2/func3/func4
# print("我们开挂啊")
# fn() # 引入 # 在引入对应的函数的上面和下面可以随意添加一些你想添加的内容
# print("还是自己玩吧")
# def func1():
# print("吃饭")
# def func2():
# print("喝汤")
# def func3():
# print("拉翔")
# def func4():
# print("睡觉")
# func(func1)

# 二、闭包
# 什么是闭包?闭包就是内层函数,对外层函数(非全局)的变量的引用,叫闭包
# def func1():
# name = "alex"
# def func2():
# print(name) # 闭包 引用上一层的变量
# func2()
# print(func2.__closure__) # (<cell at 0x01432D90: str object at 0x013BDCE0>,) 注意检验时不能带()
# func1() # alex
# 我们可以使⽤__closure__来检测函数是否是闭包. 使⽤函数名.__closure__返回cell就是
# 闭包. 返回None就不是闭包

# 问题, 如何在函数外边调⽤内部函数呢?
# def outer():
# name = "alex"
# # 内部函数
# def inner():
# print(name)
# return inner
# fn = outer() # 访问外部函数, 获取到内部函数的函数地址
# fn() # 访问内部函数

# 那如果多层嵌套呢? 很简单, 只需要⼀层⼀层的往外层返回就⾏了
# def func1():
# def func2():
# def func3():
# print("嘿嘿")
# return func3
# return func2
# func1()()()

# 由它我们可以引出闭包的好处. 由于我们在外界可以访问内部函数. 那这个时候内部函
# 数访问的时间和时机就不⼀定了, 因为在外部, 我可以选择在任意的时间去访问内部函数. 这
# 个时候. 想⼀想. 我们之前说过, 如果⼀个函数执⾏完毕. 则这个函数中的变量以及局部命名
# 空间中的内容都将会被销毁. 在闭包中. 如果变量被销毁了. 那内部函数将不能正常执⾏.
# 所以. python规定. 如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡.
# 将会常驻在内存中. 也就是说. 使⽤闭包, 可以保证外层函数中的变量在内存中常驻.
# 闭包作用总结:
# 1、保护我们局部的一个变量不受侵害
# 2、加载一个变量常驻内存中,方便后面随时调用

# 这样做有什么好处呢? 非常⼤的好处. 我们来看⼀个关于爬⾍的代码:
# from urllib.request import urlopen
# def but():
# content = urlopen("http://tv.cctv.com/").read() # 永久驻留在内存中
# def get_content():
# return content
# return get_content()
# fn = but() # 这个时候就开始加载百度的内容
# # 后面需要用到这里的内容就不需要在执行非常耗时的网络连接操作了
# content = fn() # 获取内容
# print(content)

# content2 = fn() # 重新获取内容 不需要再进行网络请求了
# print(content2) #可以反复调用content里面的内容

# 函数的注释
# def func(a,b):
# '''
#
# :param a: 第一个数
# :param b: 第二个数
# :return: 返回两数相加的和
# author:Daniel
# 2018.10.31
# '''
# print("我是func")
# return a + b
# y = func(1,5)
# print(y) # 6

# 三、迭代器
# 我们之前⼀直在⽤可迭代对象进⾏迭代操作. 那么到底什么是可迭代对象. 本⼩节主要讨
# 论可迭代对象. ⾸先我们先回顾⼀下⽬前我们所熟知的可迭代对象有哪些:
# str, list, tuple, dict, set. 那为什么我们可以称他们为可迭代对象呢? 因为他们都遵循了可
# 迭代协议.
# iterable表⽰可迭代的. 表⽰可迭代协议. 那么如何进⾏验证你的数据类型是否
# 符合可迭代协议. 我们可以通过dir函数来查看类中定义好的所有⽅法.
# 如果打印出来结果含有__iter__则为可迭代
# s = "大王叫我,来巡山啦"
# print(dir(s)) # __getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__',
# pritn(dir(str)) # 结果中也含有__iter__

# 我们发现这⼏个可以进⾏for循环的东⻄都有__iter__函数, 包括range也有. 可以⾃⼰试⼀下.
# 这是查看⼀个对象是否是可迭代对象的第⼀种办法. 我们还可以通过isinstence()函数来查
# 看⼀个对象是什么类型的
# isinstence() 的语法 xx是什么 如果是为True 如果不是为False
# l = [1, 2, 3]
# l1 = l.__iter__()
# from collections import Iterable
# from collections import Iterator
# print(isinstance(l, Iterable)) #True
# print(isinstance(l, Iterator)) #False
# 表示:l是可迭代的但是没有迭代器

# 综上. 我们可以确定. 如果对象中有__iter__函数. 那么我们认为这个对象遵守了可迭代协议.
# 就可以获取到相应的迭代器. 这⾥的__iter__是帮助我们获取到对象的迭代器. 我们使⽤迭代
# 器中的__next__()来获取到⼀个迭代器中的元素. 那么我们之前讲的for的⼯作原理到底是什
# 么?

# for 循环的机制
# 使⽤while循环+迭代器来模拟for循环(必须要掌握)
# l = lis = ["皇帝", "皇后", "太后", "皇子", "皇孙", "皇舅"]
# l1 = l.__iter__()
# while 1: # 整个while循环相当于在for循环中拿元素
# try:
# l2 = l1.__next__()
# print(l2)
# except StopIteration:
# print("over")
# break

# 总结:
# Iterable: 可迭代对象. 内部包含__iter__()函数
# Iterator: 迭代器. 内部包含__iter__() 同时包含__next__().
# 迭代器的特点:
# 1. 节省内存.
# 2. 惰性机制
# 3. 不能反复, 只能向下执⾏
posted @ 2018-10-31 16:37  我是一名劍客  阅读(193)  评论(0编辑  收藏  举报