博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
迭代器
阅读量:5117 次
发布时间:2019-06-13

本文共 8069 字,大约阅读时间需要 26 分钟。

本节主要内容:

1. 函数名的使⽤以及第⼀类对象

2. 闭包

3. 迭代器

⼀. 函数名的运⽤. 函数名是⼀个变量, 但它是⼀个特殊的变量, 与括号配合可以执⾏函数的变量.

1. 函数名的内存地址

def func():    print("呵呵")print(func) 结果:

 

2. 函数名可以赋值给其他变量

def func():    print("呵呵")print(func)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指向的就是上⾯函数2fn() # 执⾏上⾯返回的函数

⼆. 闭包

  什么是闭包? 闭包就是内层函数, 对外层函数(非全局)的变量的引⽤. 叫闭包

def func1():    name = "alex"    def func2():        print(name) # 闭包    func2()func1()结果:alex

我们可以使⽤__closure__来检测函数是否是闭包. 使⽤函数名.__closure__返回cell就是 闭包. 返回None就不是闭包

def func1():    name = "alex"    def func2():        print(name) # 闭包    func2()    print(func2.__closure__) # (
,)func1()

  问题, 如何在函数外边调⽤内部函数呢?

def outer():    name = "alex"    # 内部函数    def inner():    print(name)    return inner fn = outer() # 访问外部函数, 获取到内部函数的函数地址fn() # 访问内部函数

  那如果多层嵌套呢? 很简单, 只需要⼀层⼀层的往外层返回就⾏了

def func1():    def func2():      def func3():         print("嘿嘿")     return func3   return func2func1()()()

  由它我们可以引出闭包的好处. 由于我们在外界可以访问内部函数. 那这个时候内部函 数访问的时间和时机就不⼀定了, 因为在外部, 我可以选择在任意的时间去访问内部函数. 这 个时候. 想⼀想. 我们之前说过, 如果⼀个函数执⾏完毕. 则这个函数中的变量以及局部命名 空间中的内容都将会被销毁. 在闭包中. 如果变量被销毁了. 那内部函数将不能正常执⾏. 所 以. python规定. 如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡. 将会常驻在内存中. 也就是说. 使⽤闭包, 可以保证外层函数中的变量在内存中常驻. 这样做 有什么好处呢? 非常⼤的好处. 我们来看⼀个关于爬⾍的代码:

from urllib.request import urlopendef but():    content = urlopen("http://www.xiaohua100.cn/index.html").read()    def get_content():        return content    return get_contentfn = but() # 这个时候就开始加载校花100的内容# 后⾯需要⽤到这⾥⾯的内容就不需要在执⾏⾮常耗时的⽹络连接操作了content = fn() # 获取内容print(content)content2 = fn() # 重新获取内容print(content2)

综上, 闭包的作⽤就是让⼀个变量能够常驻内存. 供后⾯的程序使⽤.

三. 迭代器

   我们之前⼀直在⽤可迭代对象进⾏迭代操作. 那么到底什么是可迭代对象. 本⼩节主要讨 论可迭代对象. ⾸先我们先回顾⼀下⽬前我们所熟知的可迭代对象有哪些:

   str, list, tuple, dict, set. 那为什么我们可以称他们为可迭代对象呢? 因为他们都遵循了可 迭代协议. 什么是可迭代协议. ⾸先我们先看⼀段错误代码:

# 对的s = "abc"for c in s:    print(c)# 错的for i in 123:    print(i)结果:Traceback (most recent call last):    File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 8, in
for i in 123:TypeError: 'int' object is not iterable

 注意看报错信息中有这样⼀句话. 'int' object is not iterable . 翻译过来就是整数类型对象 是不可迭代的. iterable表⽰可迭代的. 表⽰可迭代协议. 那么如何进⾏验证你的数据类型是否 符合可迭代协议. 我们可以通过dir函数来查看类中定义好的所有⽅法

s = "我的哈哈哈"print(dir(s)) # 可以打印对象中的⽅法和函数print(dir(str)) # 也可以打印类中声明的⽅法和函数

在打印结果中. 寻找__iter__ 如果能找到. 那么这个类的对象就是⼀个可迭代对象.

['__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']

我们发现在字符串中可以找到__iter__. 继续看⼀下list, tuple, dict, set

print(dir(tuple))print(dir(list))print(dir(open("护⼠少妇嫩模.txt"))) # ⽂件对象print(dir(set))print(dir(dict))结果:['__add__', '__class__', '__contains__', '__delattr__', '__dir__','__doc__', '__eq__', '__format__', '__ge__', '__getattribute__','__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__','__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__','__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__','__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count','index']['__add__', '__class__', '__contains__', '__delattr__', '__delitem__','__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__','__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__','__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__','__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__','__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__','__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count','extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__','__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__','__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__','__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__','__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__','__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed','_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing','buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno','flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read','readable', 'readline', 'readlines', 'seek', 'seekable', 'tell','truncate', 'writable', 'write', 'writelines']['__and__', '__class__', '__contains__', '__delattr__', '__dir__','__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__','__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__','__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__','__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__','__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__','__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear','copy', 'difference', 'difference_update', 'discard', 'intersection','intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop','remove', 'symmetric_difference', 'symmetric_difference_update', 'union','update']['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__','__doc__', '__eq__', '__format__', '__ge__', '__getattribute__','__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__','__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__','__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__','__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys','get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

    我们发现这⼏个可以进⾏for循环的东⻄都有__iter__函数, 包括range也有. 可以⾃⼰试⼀ 下.

    这是查看⼀个对象是否是可迭代对象的第⼀种办法. 我们还可以通过isinstence()函数来查 看⼀个对象是什么类型的

l = [1,2,3]l_iter = l.__iter__()from collections import Iterablefrom collections import Iteratorprint(isinstance(l,Iterable)) #Trueprint(isinstance(l,Iterator)) #Falseprint(isinstance(l_iter,Iterator)) #Trueprint(isinstance(l_iter,Iterable)) #True

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

s = "我爱北京天安⻔"c = s.__iter__() # 获取迭代器print(c.__next__()) # 使⽤迭代器进⾏迭代. 获取⼀个元素 我print(c.__next__()) # 爱print(c.__next__()) # 北print(c.__next__()) # 京print(c.__next__()) # 天print(c.__next__()) # 安print(c.__next__()) # ⻔print(c.__next__()) # StopIteration

  for循环的机制:

for i in [1,2,3]:    print(i)

使⽤while循环+迭代器来模拟for循环(必须要掌握)

 

lst = [1,2,3]lst_iter = lst.__iter__()while True:    try:    i = lst_iter.__next__()        print(i)    except StopIteration:    break

总结:

Iterable: 可迭代对象. 内部包含__iter__()函数

Iterator: 迭代器. 内部包含__iter__() 同时包含__next__().

迭代器的特点:

1. 节省内存.

2. 惰性机制

3. 不能反复, 只能向下执⾏.

我们可以把要迭代的内容当成⼦弹. 然后呢. 获取到迭代器__iter__(), 就把⼦弹都装在弹夹 中. 然后发射就是__next__()把每⼀个⼦弹(元素)打出来. 也就是说, for循环的时候. ⼀开始的 时候是__iter__()来获取迭代器. 后⾯每次获取元素都是通过__next__()来完成的. 当程序遇到 StopIteration将结束循环.

 

转载于:https://www.cnblogs.com/y0413/p/9892466.html

你可能感兴趣的文章
devexpress中如何给TabPage控件的Tab定义背景色
查看>>
linux如何复制文件夹和移动文件夹
查看>>
WAMP环境搭建(windows+apache2.4+mysql5.7+php7)
查看>>
测试Markdown
查看>>
poj 1113 Wall
查看>>
tcp三次握手
查看>>
IntelliJ IDEA 代码字体大小的快捷键设置放大缩小(很实用)(图文详解)
查看>>
HTTP之gRPC
查看>>
Entity Framework 学习 DataBase First
查看>>
面向对象建模方法与数据库建模方法的比较
查看>>
library cache lock and user password
查看>>
面试题7-用两个栈实现队列
查看>>
Shell参数选项解析
查看>>
unity编辑器扩展_08(创建自定义窗口)
查看>>
linux上apache安装过程
查看>>
《那些年啊,那些事——一个程序员的奋斗史》开始预售了~~!
查看>>
sql 大写
查看>>
MyBatis-resultType 与 resultMap 中的几种返回类型
查看>>
Ubuntu16.04LTS中使用 apt-get install 出现错误 Could not get lock /var/lib/dpkg/lock 的解决方案...
查看>>
关于mongodb的aggregate
查看>>