编程range是什么意思,range series
迭代器是最常用的设计模式之一,在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=range(5) #即range (0,5) range (0,5) len (a) 5 for x in a: 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错误回溯(最近一次调用last).type error:“float”对象不能解释为整数# (3)序列操作b=range (1,10) b [0] 1b [:-3] range (1,7) b [0]=2 typeerror回溯(最近一次调用last).type error:“range”对象不支持项赋值# (4)不是迭代器hasattr(range(3),_ _ ITER _ _) true hasattr (range (3), _ _ next _ _ )false has attr(ITER(range(3), _ _ next _ _) true copy code 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(range(1,6,2),range (2,7,2)): print (I,end=) (1,2) (3,4) (5,6)复制代码。也就是说,作为初级生产者,range()方法生产的原料有很大的用途。
你觉得这样的解读合理吗?欢迎和我讨论这个话题。
3.什么是范围类型?以上是我对“range()为什么不产生迭代器”的回答。顺着这个思路,我研究了它生成的range对象。我一研究就发现这个range对象也不简单。
第一个奇怪的是,它是一个不可变的序列!我从来没有注意到这一点。虽然我从来没有想过修改range()的值,但是这个不可修改的特性还是让我很惊讶。
翻翻文件,官方划分是——有三种基本的序列类型:列表、元组和范围(range)对象。(There are three basic sequence types: lists, tuples, and range objects.)。
我没注意到这个。原来范围类型是和链表、元组一样状态的基本序列!我一直记得字符串是不可变的序列类型,但是我从来没有想过这里有不可变的序列类型。
那 range 序列跟其它序列类型有什么差异呢?
常用序列支持的操作有12种,文章《你真的知道Python的字符串是什么吗?》中有提到。范围序列只支持其中的10个,不支持加法拼接和乘法重复。
range(2) range(3) -类型错误回溯(最近一次调用).TypeError:不支持的操作数类型:“range”和“range”range(2)* 2-type error回溯(最近一次调用最后一次).typeerror:不支持*:“range”和“int”的操作数类型。请复制代码。那么问题来了:它也是一个不可变的序列。为什么字符串和元组支持以上两种操作,而范围序列却不支持?虽然不可变序列不能直接修改,但是我们可以把它们复制到新的序列中进行操作。为什么range object连这个都不支持?
且看公文的解释:
.因为range对象只能表示遵循严格模式的序列,而重复和连接通常会违反该模式。
原因是range对象只代表一个遵循严格模式的序列,重复和拼接通常会破坏这种模式。
问题的关键在于范围序列的模式。仔细想想其实是指一个等差数列(喵,我高中数学知识还没忘.),拼接两个等差数列或者重复拼接一个等差数列。想想真的不合适,这也是range类型不支持这两种操作的原因。可以推断,其他修改动作也会破坏等差数列的结构,所以干脆不要修改。
4.总结回顾全文,得到两个冷门结论:range 是可迭代对象而不是迭代器;range 对象是不可变的等差序列。。
如果只是看结论,可能感觉不到,甚至会说没什么大不了的。但如果我问,为什么range不是迭代器,为什么range是不可变序列?这两个问题还能给出一个不言自明的设计思路吗?(PS:我决定了。如果我有机会采访别人,我需要问这两个问题。哎~)
由于range对象微妙而有趣的特性,我认为这篇文章值得一写。本文写的是迭代器的系列文章,所以对迭代器的基础知识介绍不多。请查看以前的文章。此外,还有一个特殊的迭代器也值得单独编写,那就是生成器。敬请期待后续推文~
猜猜你想看什么:
高级Python:迭代器和迭代器切片
Python高级:设计模式的迭代器模式
你真的知道Python的字符串是什么吗?
官方文件:t.cn/EGMzJt8
-
本文原创发布于微信官方账号【Python猫】微信,后台回复“爱学习”免费获得20本精选电子书。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。