IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 【Python】再来聊一聊这道面试题:Python 2和Python 3中range()有何区别? -> 正文阅读

[Python知识库]【Python】再来聊一聊这道面试题:Python 2和Python 3中range()有何区别?

一,经典面试题

在python面试题中有一道经典的基础面试题:Python 2和Python 3中range()有何区别?
相信大家也都知道答案了,Python2.x range() 函数可创建一个整数列表,Python3 range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型。

迭代是Python最强大的功能之一,平时的开发都会使用到迭代,就再来聊一聊Python这个强大的功能。

二,再来聊一聊迭代器与生成器

平时自学的时候都会使用到迭代,但看到可迭代对象(iterable)、迭代器(iterator)和生成器(generator)这三个名词时,完全懵逼了,也没深入研究下。现在以自己的理解来详解,错误之处,大佬们帮忙指出。

(一)可迭代对象

实现了__iter__()方法的对象就叫做可迭代对象。iter()方法的作用就是返回一个迭代器对象。

from collections import abc

class Foo(object):
    def __iter__(self):
        pass

if __name__ == "__main__":
    f = Foo()
    print(issubclass(Foo, abc.Iterable))    # True
    print(isinstance(f, abc.Iterable))    # True

直观理解就是能用for循环进行迭代的对象就是可迭代对象。比如:字符串,列表,元祖,字典,集合等等,都是可迭代对象。

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

(二)迭代器

可迭代对象是实现了__iter__()方法的对象,而迭代器(Iterator)则是实现了__iter__()和__next__()方法的对象,__iter__返回迭代器自身,__next__返回容器中的下一个值。这种可以被next()调用并不断返回下一个值的对象称为迭代器。迭代器一定是可迭代对象,反过来则不一定成立。用iter()函数可以把list、dict、str等Iterable变成Iterator.

    x = [1, 2, 3]
    x_it = iter(x)
    print(type(x_it))
    for i in x_it:
        print(i)

输出结果
<class ‘list_iterator’>
1
2
3
除了通过for循环,还有调用next() 方法获取下一个值,

    x = [1, 2, 3]
    x_it = iter(x)
    print(next(x_it)) # 1
    print(next(x_it)) # 2
    print(next(x_it)) # 3 
    print(next(x_it)) # 迭代器里面的内容已经空 捕获 StopIteration 异常

前三个next都获取到对应的值,但是再获取下一个值时,捕获异常,这是因为此时迭代器里面的内容已经空。如果想再次迭代,那就要调用 iter(…),传入之前构建迭代器的可迭代对象

下面是一个斐波那契数列迭代器:实现__iter__()和__next__()方法,其中__next__()抛出StopIteration异常,
class FibIterator(object):
    def __init__(self, num):
        self.ind = 1
        self.pre = 0
        self.cur = 1
        self.num = num

    def __iter__(self):
        return self

    def __next__(self):
        if self.ind <= self.num:
            tmp = self.cur
            self.cur += self.pre
            self.pre = tmp
            self.ind += 1
            return self.cur
        else:
            raise StopIteration

if __name__ == "__main__":
    fib = FibIterator(5)
    print(issubclass(FibIterator, abc.Iterable))
    print(next(fib))
    print(next(fib))
    print(next(fib))
    print(next(fib))
    print(next(fib))
    print(next(fib))

执行结果:

True
1
2
3
5
8
Traceback (most recent call last):
  File "E:/PycharmProjects/数据结构与算法/test.py", line 159, in <module>
    print(next(fib))
  File "E:/PycharmProjects/数据结构与算法/test.py", line 148, in __next__
    raise StopIteration

(三)生成器与生成器表达式

生成器

生成器是通过一个或多个yield表达式构成的函数,生成器可以看作是一种特殊的迭代器,它不需要再像上面的类一样写__iter__()和__next__()方法了,只需要一个yiled关键字,用生成器构建斐波那契数列。

class FibIterator(object):
    def __init__(self, num):
        self.ind = 1
        self.pre = 0
        self.cur = 1
        self.num = num

    def __iter__(self):
        while self.ind <= self.num:
            tmp = self.cur
            self.cur += self.pre
            self.pre = tmp
            self.ind += 1
            yield self.cur
            
if __name__ == "__main__":
    fib = FibIterator(5)
    print(fib.__iter__())
    for f in fib:
        print(f)

执行结果
<generator object FibIterator.iter at 0x00000000027DA518>
1
2
3
5
8
在__iter__()中使用yield,当调用这个函数就会创建一个生成器对象,生成器中的yield相当于一个断点,执行到此返回一个值后暂停,从而实现next取值,for循环隐式调用next()。

生成器表达式

生成器表达式是列表推倒式的生成器版本,看起来像列表推导式,但是它返回的是一个生成器对象而不是列表对象。

if __name__ == "__main__":
    a = (x**2 for x in range(10))
    print(a)   # <generator object <genexpr> at 0x00000000027FA518>

(四)迭代器与生成器的区别

生成器
生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭代器不一定是生成器)。如果一个函数包含yield关键字,这个函数就会变为一个生成器。
生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。每次调用next方法,生成器从上一次的位置开始执行,获取下一个值。
迭代器
迭代器是一种实现__iter__()和__next__()方法的对象。它包含了一组元素,当执行next()操作时,返回其中一个元素。当所有元素都被返回后,再执行next()报异常—StopIteration。
区别
1,实现方式不同。一个函数,一个对象。
2,生成器生成元素,可以通过迭代器来访问这些元素,可以认为通过迭代器输出生成器的内容。

(五)强大的内置迭代器方法

zip()

zip() 方法可以同时迭代多个序列,并各取一个元素,生成一个可返回元组的迭代器。此迭代器的长度以较短序列的长度保持一致,若想生成较长序列的长度,需要使用 itertools 模块的 zip_longest() 方法。

import itertools

a = [1, 2, 3]
b = ['a', 'b', 'c', 'd']

for i in zip(a,b):
    print(i,end=" ")  # (1, 'a') (2, 'b') (3, 'c') 

# 空缺值以 None 填补
for i in itertools.zip_longest(a,b):
    print(i,end=" ")  # (1, 'a') (2, 'b') (3, 'c') (None, 'd') 
enumerate()

enumerate() 方法接收一个序列类型参数,**生成一个可返回元组的迭代器,元组内容是下标及其对应的元素值。**它还可接收一个可选参数,指定下标的起始值,默认是0 。

days = ['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun']

for i in enumerate(days):
    print(i,end=" ")  
#输出结果:(0, 'Mon') (1, 'Tue') (2, 'Wed') (3, 'Thur') (4, 'Fri') (5, 'Sat') (6, 'Sun')
# 修改开始索引值
for i in enumerate(days, start=7):
    print(i,end=" ")  
#输出结果:(7, 'Mon') (8, 'Tue') (9, 'Wed') (10, 'Thur') (11, 'Fri') (12, 'Sat') (13, 'Sun') 
map()

map() 方法的参数是一个函数及一个或多个可迭代对象,**它会将可迭代对象的元素映射到该函数中,然后迭代地运行该函数,返回结果也是一个迭代器。**当存在多个可迭代对象参数时,迭代长度等于较短对象的长度。

from collections import abc
def square(x):
    return x ** 2

l = map(square, [1, 2, 3, 4, 5])
print(isinstance(l,abc.Iterable))  # True 可迭代对象
print(list(l))
# 输出结果:[1, 4, 9, 16, 25]

m = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10, 2])
print(isinstance(m,abc.Iterable))  # True 可迭代对象
print(list(m))
# 输出结果:[3, 7, 11, 15, 19]
filter()

filter() 方法的参数是一个判断函数及一个可迭代对象,遍历可迭代对象执行判断函数,过滤下判断为True 的元素,与它相对,若想保留判断为 False 的元素,可使用 itertoole 模块的 filterfalse() 方法。

import itertools

ft = filter(lambda x: x%2, range(10))
ff = itertools.filterfalse(lambda x: x%2, range(10))

print(isinstance(ft,abc.Iterable))  # True
for i in ft:
    print(i,end=" ")
# 输出结果:1 3 5 7 9

print(isinstance(ff,abc.Iterable))  # True
for i in ff:
    print(i,end=" ")
# 输出结果:0 2 4 6 8

(六) itertools 模块

除了前面所说的内置迭代器方法,还有itertools中的函数大多是返回各种迭代器对象,其中很多函数的作用我们平时要写很多代码才能达到,而在运行效率上反而更低,使用itertools中的函数可以轻松高效实现。

itertools.accumulate 累加
x = itertools.accumulate(range(10))
print(list(range(10)))
# 输出结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(list(x)) 
# 输出结果:[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
itertools.chain 连接多个迭代器。
a = ['a','b','c']
b = [1,2,3,4]
x = itertools.chain(a, b)
print(list(x))  # 输出结果:['a', 'b', 'c', 1, 2, 3, 4]
itertools.permutations 指定数目的元素排列结果
a = ['a','b','c']
a1 = itertools.permutations(a,3)   # 3 参与排列元素个数
print(list(a1))  
# 输出结果:[('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), 
# ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]
itertools.combinations 指定数目的元素不重复的所有组合
a = ['a','b','c']
a1 = itertools.combinations(a,2)
print(list(a1))  
# 输出结果:[('a', 'b'), ('a', 'c'), ('b', 'c')]
itertools.combinations_with_replacement 允许重复元素的组合
a = ['a','b','c']
a1 = itertools.combinations_with_replacement  (a,2)
print(list(a1))  
# 输出结果:[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')]

itertools 中有很多方法,这里就不一一列举,可以参考 官方文档

参考

https://blog.csdn.net/chinesehuazhou2/article/details/85643960
《Python Cookbook》第三版
https://www.cnblogs.com/fmgao-technology/p/9064301.html

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:12:00  更:2021-08-09 10:13:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 1:30:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计