Python之迭代器

函数名的应用

函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量。

1. 函数名的内存地址

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


print(func)

结果:

<function func at 0x0000000000A5D2F0>

Process finished with exit code 0

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

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


a = func
a()

结果:

呵呵

Process finished with exit code 0

3. 函数名可以当做容器类元素

def func1():
    print("呵呵")


def func2():
    print("呵呵")


def func3():
    print("呵呵")


def func4():
    print("呵呵")


lst = [func1, func2, func3, func4]
for i in lst:
    i()

结果:

呵呵
呵呵
呵呵
呵呵

Process finished with exit code 0

4. 函数名可以当做函数的参数

def func():
    print("吃了么")


def func2(fn):
    print("我是func2")
    fn()  # 执⾏传递过来的fn
    print("我是func2")


func2(func)  # 把函数func当成参数传递给func2的参数fn

结果:

我是func2
吃了么
我是func2

Process finished with exit code 0

闭包

闭包就是内层函数,对外层函数(非全局)的变量的引用,叫闭包。

def func1():
    name = "Python"

    def func2():
        print(name)  # 闭包

    func2()


func1()

结果:

Python

Process finished with exit code 0

注意:我们可以使用__closure__来检测函数是否是闭包,使用函数名.__closure__返回cell就是闭包,返回None就不是闭包。

def func1():
    name = "Python"

    def func2():
        print(name)  # 闭包

    func2()
    print(func2.__closure__)  # 检验是否闭包


func1()

结果:

Python
(<cell at 0x00000000007B5C48: str object at 0x000000000069B928>,)

Process finished with exit code 0

那么问题来了,如何利用外部函数调用内部函数呢?

def outer():
    name = "Python"

    # 内部函数
    def inner():
        print(name)

    return inner


fn = outer()  # 访问外部函数, 获取到内部函数的函数地址
fn()

结果:

Python

Process finished with exit code 0

在进行多次嵌套之后,我们应该如何调用内部函数呢?很简单,只需要一层一层的往外面调用即可。

def func1():
    def func2():
        def func3():
            print("Python")

        return func3

    return func2


func1()()()

结果:

Python

Process finished with exit code 0

闭包的作用:

在一般情况下,函数体执行完毕后解释器会将内存回收,但是当内部函数如果可能有需要调用的外部数据时,这些外部数据在内存中不会消亡,会常驻内存。总之就是确保外部函数内存不会被解释器回收。

接下来演示一个爬虫的实例:

from urllib.request import urlopen


def but():
    content = urlopen("http://www.xiaohua100.cn/index.html").read()

    def get_content():
        return content

    return get_content


fn = but()  # 这个时候就开始加载校花100的内容
content = fn()  # 获取内容
print(content)
content2 = fn()  # 重新获取内容
print(content2)

结果:

(爬到的是网站站点的的前端代码,太长故而不做演示。)

迭代器

目前所研究的我们所熟知的可迭代对象有str,list,tuple,dict,set,文件句柄等。

为什么int类型不是可迭代对象呢,我们试图这样做一下,看看会发生什么。

s = "abc"
for c in s:
    print(c)
# 错的
for i in 123:
    print(i)

结果:

a
b
c
Traceback (most recent call last):
  File "D:/Zhenxian/Python/DayTwelve/Basic.py", line 252, in <module>
    for i in 123:
TypeError: 'int' object is not iterable

Process finished with exit code 1

容易看出,字符串对象可以被迭代,但是int类型迭代会报错。

倘若我们不能了解某些对象存在的方法,我们可以通过使用dir()函数要查看该对象可存在的操作。

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

结果:

['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__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']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__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']

Process finished with exit code 0

我们再试试list对象和元组对象:

lst = ["Python", "Java", "Ruby"]
tu = (1, 2, 3, 4, 5)
print(dir(lst))
print(dir(tu))

结果:

['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__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']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']

Process finished with exit code 0

我们很容易看出这些可迭代对象里面都有__iter__函数,如果拥有这个函数,那这个对象就是可迭代的。使用__iter__可以帮助我们获取对象中的迭代器,我们使用迭代器中的__next__()来获取一个迭代器中的元素。

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

结果:

Traceback (most recent call last):

  File "D:/AiBentao/Python/DayTwelve/Basic.py", line 274, in <module>



    print(c.__next__())  # StopIteration


StopIteration

Process finished with exit code 1

细心的同学可能已经发现了,本次示例代码是存在问题的,运行结果抛出了StopIteration的错误。

分析:字符串有七个字符,然而我们使用迭代器迭代了八次,相当于迭代结果已经完了,但是我们继续操作__next__(),就会出现这样的错误。

为了避免这样的错误,我们将通过try操作来捕捉,使得程序有条不紊的运行。

s = "我爱北京天安门"
c = s.__iter__()  # 获取迭代器
while True:
    try:
        i = c.__next__()
        print(i)
    except StopIteration:
        break

结果:







Process finished with exit code 0

总结

Iterable:可迭代对象。

内部包含__iter__()函数

Iterato:迭代器

内部包含__iter__() 同时包含__next__()。

 

迭代器的特点:

1. 节省内存。

2. 惰性机制 。

3. 不能反复,只能向下执行。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值