大多数range函数经常出现在for循环中,可以在for循环中用作索引。下面这篇文章主要介绍Python中range函数的基本用法,通过示例代码非常详细的介绍。有需要的朋友可以参考一下。
目录
前言1。什么是range()?2.为什么range()不产生迭代器?3.什么是范围类型?4.总结附件:Python的range()函数的历史总结
前言
迭代器是最常用的设计模式之一,在Python中随处可见。我们经常使用它,却不一定意识到它的存在。在一系列关于迭代器的文章中(链接见文章末尾),我提到了至少23种生成迭代器的方法。有些方法是专门用来生成迭代器的,有些则是“偷偷”用迭代器来解决其他问题。
在系统学习迭代器之前,我一直以为range()方法也是用来生成迭代器的,现在突然发现它只生成迭代器,不生成迭代器!(Python 2中的PS: range()生成列表,本文基于Python3,生成迭代对象)
所以,我有这个问题:为什么range()不生成迭代器?在寻找答案的过程中,我发现自己对值域的类型有一些误解。所以这篇文章会让你对range有一个全面的了解,期待和你一起学习进步。
1、range() 是什么?
其语法:range (start,stop [,step]);Start是指计数的起始值,默认为0;Stop是指计数结束值,但不包括stop;Step是步长,默认为1,不能为0。range()方法生成一个左闭右开的整数范围。
A=范围(5) #即范围(0,5)
a
范围(0,5)
镜头(a)
五
对于a中的x:
print(x,end=' ')
0 1 2 3 4
对于range()函数,有几点需要注意:(1)它代表左闭右开区间;(2)它接收的参数必须是整数、负数,但不能是浮点数等类型;(3)是不可变的序列类型,可以判断元素、查找元素、切片元素等。但不能修改元素;(4)它是迭代对象,但不是迭代器。
# (1)左侧关闭,右侧打开
对于范围(3,6)中的I:
print(i,end=' ')
3 4 5
# (2)参数类型
对于范围(-8,-2,2)内的I:
print(i,end=' ')
-8 -6 -4
范围(2.2)
-
类型错误回溯(最近一次调用)
.
type error:“float”对象不能解释为整数
# (3)顺序操作
b=范围(1,10)
b[0]
一个
b[:-3]
范围(1,7)
b[0]=2
类型错误回溯(最近一次调用)
.
type error:“range”对象不支持项分配
# (4)不是迭代器
hasattr(范围(3),' __iter__ ')
真实的
hasattr(range(3),' __next__ ')
错误的
hasattr(iter(range(3)),' __next__ ')
真实的
2、 为什么range()不生产迭代器?
可以获取迭代器的内置方法有很多,比如zip()、enumerate()、map()、filter()和reversed()等。但是像range()这样只获取iterable对象的方法只有一个(如果有反例,请告知)。这就是我的知识出错的地方。
在for- loop遍历中,迭代器和迭代器的性能是一样的,即都是惰性求值,在空间复杂度和时间复杂度上没有区别。我总结了一下,两者的区别是“两个区别在一起”:相同的是可以惰性迭代,不同的是iterable对象不支持自遍历(即next()方法),而迭代器本身不支持切片(即__getitem__()方法)。
虽然有这些区别,但是很难断定哪个更好。现在微妙之处在于,为什么迭代器是为所有五个内置方法设计的,而range()方法却被设计成可迭代对象?把他们都统一起来不是更好吗?
事实上,Pyhton为了标准化已经做了很多这样的事情。比如Python2有两个方法,range()和xrange(),而Python3杀了其中一个,用的是“以桃代桃”的方法。为什么不更标准一点,让range()生成迭代器?
关于这个问题,我还没有找到官方的解释。以下纯属我个人观点。
zip()等方法都需要接收某些iterable对象的参数,这是一个对它们进行再处理的过程。所以,他们也想立刻产生一定的结果,所以Python开发者把这个结果设计成了迭代器。这也有一个好处,当作为参数的iterable对象改变时,结果迭代器不会被错误地使用,因为它是消耗性的。
range()方法不同。它接收的参数不是迭代的对象,而是一个初始处理的过程。因此,它被设计为迭代对象,可以直接使用或用于其他再处理目的。例如,zip()这样的方法可以完全接收range类型的参数。
对于zip中的I(范围(1,6,2),范围(2,7,2)):
print(i,end=' ')
(1, 2)(3, 4)(5, 6)
也就是说,range()方法是一个初级生产者,它生产的原料有很大的用处。过早把它变成迭代器无疑是画蛇添足的行为。
你觉得这样的解读合理吗?欢迎和我讨论这个话题。
3、range 类型是什么?
以上是我对“range()为什么不产生迭代器”的回答。顺着这个思路,我研究了它生成的range对象。我一研究就发现这个range对象也不简单。
第一个奇怪的是,它是一个不可变的序列!我从来没有注意到这一点。虽然我从来没有想过修改range()的值,但是这个不可修改的特性还是让我很惊讶。
翻翻文件,官方划分是——有三种基本的序列类型:列表、元组和范围(range)对象。(There are three basic sequence types: lists, tuples, and range objects.) 。
我没注意到这个。原来范围类型是和链表、元组状态一样的基本序列!我一直记得字符串是不可变的序列类型,但是我从来没有想过这里有不可变的序列类型。
范围序列和其他序列类型有什么区别?
通用序列支持12种操作。范围序列只支持其中的10个,不支持加法拼接和乘法重复。
范围(2)范围(3)
-
类型错误回溯(最近一次调用)
.
TypeError:不支持的操作数类型:“range”和“range”
范围(2)*2
-
类型错误回溯(最近一次调用)
.
TypeError:不支持*:“range”和“int”的操作数类型
那么问题来了:它也是一个不可变的序列。为什么字符串和元组支持以上两种运算,而范围序列不支持?虽然不可变序列不能直接修改,但是我们可以把它们复制到新的序列中进行操作。为什么range object连这个都不支持?
且看公文的解释:
…因为范围对象只能表示遵循严格模式的序列,而重复和连接通常会违反该模式。
原因是range对象只表示遵循严格模式的序列,重复和拼接通常会破坏这种模式…
问题的关键在于范围序列的模式。仔细想想,其实就是一个等差数列(喵,我高中数学知识没忘……),拼接两个等差数列,或者反复拼接一个等差数列。想想真的不合适,这也是range类型不支持这两种操作的原因。可以推断,其他修改动作也会破坏等差数列的结构,所以干脆不要修改。
4、小结
回顾全文,得到两个冷门结论:range 是可迭代对象而不是迭代器;range 对象是不可变的等差序列。。
如果只是看结论,可能感觉不到,甚至会说没什么大不了的。但如果我问,为什么range不是迭代器,为什么range是不可变序列?这两个问题还能给出一个不言自明的设计思路吗?(PS:我决定了。如果我有机会采访别人,我需要问这两个问题。哎~)
由于range对象微妙而有趣的特性,我认为这篇文章值得一写。本文写的是迭代器的系列文章,所以对迭代器的基础知识介绍不多。另外,还有一个特殊的迭代器值得单独编写,那就是生成器。
附:Python的range()函数的历史
虽然Python 2中的range()和Python 3中的range()可能共用一个名字,但它们是完全不同的动物。实际上,Python 3中的range()只是Python 2中名为xrange的函数的重命名版本。
最初,range()和xrange()都生成可以被for循环遍历的数字,但是前者一次生成所有这些数字的列表,而后者懒洋洋地生成数字,这意味着在需要时一次返回一个数字。
挂一个巨大的列表要占用内存,所以xrange()代替range()、name和一切也就不足为奇了。你可以在PEP 3100中阅读更多关于这个决定和xrange() vs range()的背景。
注意:PEP代表Python增强提案。Pep是一个涵盖广泛主题的文档,包括建议的新功能、风格、治理和理念。
有很多。PEP 1解释了它们是如何工作的,是一个很好的起点。
总结
关于Python中range函数的基本用法,本文到此结束。有关Python中range函数用法的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望你以后能支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。