xrangerangepython
㈠ python学习之惰性求值
惰性求值,也就是延迟求值,表达式不会在它被绑定到变量之后就立即求值,而是等用到时再求值。这个特性可以解决一些巨大甚至无限的集合列表,如菲波那切数列、几十G的文件等等。延迟求值的一个好处是能够建立可计算的无限列表而没有妨碍计算的无限循环或大小问题。
Python中的很多方法没有直接返回列表,而是返回了一个可迭代的generator
(生成器)对象,这便是python的惰性求值,因为在创建一个很大的列表时,对内存的开销非常大,太大时python会直接报错,举个:chestnut::range()方法是产生一个指定范围列表,在Python3之前,该方法直接产生一个列表,xrange()产生一个生成器:
>>>xrange(100)
xrange(100)
>>>range(100)
[0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
当参数里面的值足够大时,range()产生了一个巨大的列表,这是内存会吃不消,等待一段时间后程序会直接被Kill掉:
>>>foriinrange(999999999999):
...
printi
...
Killed:
9
占满内存
用xrange()方法就不回出现这种问题,并且可以一直运行:
>>>foriinxrange(999999999999):
...
printi
...
0
1
2
3
4
5
6
7
8
9
10...
在Python3中range已经被改为了xrange,所以在python3中可以放心使用range().
惰性求值不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁
还有前文所说的list comprehension语句,在两边放上[],会产生别表,如果数据源很长则会报内存错误:
>>>
print [iforiinrange(9999999999999999)]
Python(1627,0x7fffe5b713c0)
malloc: *** mach_vm_map(size=80000000000000000) failed
(errorcode=3)
***error:
can't allocate region
***seta
breakpointinmalloc_error_breaktodebug
Traceback
(most recentcalllast):
File "",
line 1,in<</span>mole>
MemoryError
这样直接产生列表没有效率,为了创建生成器对象,可以在list
comprehension两边放上(),这样它就有了惰性求值的特性。
>>>
print((ifori
inrange(99999999999999)))
使用next()内建函数访问生成器里的元素:
num =
(iforiinrange(5))
>>>
num
>>>>
next(num)
0
>>>
next(num)
1
>>>
for j in range(4):
...
print(next(num))
...
2
3
4
Traceback
(most recent call last):
File "",
line 2,in<</span>mole>
StopIteration
当访问到最后元素时,再调用next(),Python将会抛出StopIteration异常。Python正是根据是否检查到这个异常来决定是否停止迭代。
step1 =
someLongOperation1()step2 = someLongOperation2()step3 =
concatenate(step1, step2)
以上代码需要分别执行一二两步操作,第三步用到一二两步的结果,在Pyhton中会有序的执行这些函数:首先是someLongOperation1,然后someLongOperation2,最后concatenate,如果确保没有函数修改或依赖于全局变量,第一二步可以被并行执行。假设我们不想并行运行这两个函数,我们只在其他函数依赖于step1和step2时才需要执行这两个函数。我们甚至在concatenate调用之前都不必执行他们,可以把他们的求值延迟到concatenate函数内实际用到他们的位置。如果函数中用到了if分支语句,条件无关step1和step2则可以尽量将判断条件放前面以减少不必要的计算:
step1 =
someLongOperation1()
step2 =
someLongOperation2()ifcondition:
step3 =
concatenate(step1, step2)
换为:ifcondition:
step1 =
someLongOperation1()
step2 =
someLongOperation2()
step3 =
concatenate(step1, step2)
如果concatenate是一个带有条件分支的函数并且有的分支中只用了两个参数中的一个,另一个参数就永远没有必要被求值。
㈡ python 的range()函数怎么使用,为什么单独运行print(range(1,5))输出还是range(1,5),而不是[1,2,3,4]
print("类型:",type(range(1,5)))
print(range.mro())
看结果:
㈢ python 涓镄剅ange杩斿洖镄勬槸浠涔埚垪琛
鍦≒ython3浠ュ悗锛宺ange杩斿洖镄勬槸涓涓鍙杩浠g殑瀵硅薄锛屽苟涓嶆槸鍒楄〃锛岄渶瑕佸硅繑锲炵殑瀵硅薄杩涜宭ist杞鎹锛屽湪2镄勬椂鍊檙ange杩斿洖镄勬槸list锛寈range鍜3镄剅ange鐩镐技锛岃矊浼3鎶妜range鍙栨秷浜
㈣ python版本有什么不同
对比python2和python3,两者的差异如下:
1. Python3 对 Unicode 字符的原生支持。
Python2 中使用 ASCII 码作为默认编码方式导致 string 有两种类型 str 和 unicode,Python3 只
支持 unicode 的 string。Python2 和 Python3 字节和字符对应关系为:
2. Python3 采用的是绝对路径的方式进行 import
Python2 中相对路径的 import 会导致标准库导入变得困难(想象一下,同一目录下有 file.py,如
何同时导入这个文件和标准库 file)。Python3 中这一点将被修改,如果还需要导入同一目录的文件必
须使用绝对路径,否则只能使用相关导入的方式来进行导入。
推荐学习《python教程》
3. Python2 中存在老式类和新式类的区别,Python3 统一采用新式类。新式类声明要求继承 object,
必须用新式类应用多重继承。
4. Python3 使用更加严格的缩进。Python2 的缩进机制中,1 个 tab 和 8 个 space 是等价的,所
以在缩进中可以同时允许 tab 和 space 在代码中共存。这种等价机制会导致部分 IDE 使用存在问题。
Python3 中 1 个 tab 只能找另外一个 tab 替代,因此 tab 和 space 共存会导致报错:TabError:
inconsistent use of tabs and spaces in indentation.
废弃类差异
1. print 语句被 Python3 废弃,统一使用 print 函数
2. exec 语句被 python3 废弃,统一使用 exec 函数
3. execfile 语句被 Python3 废弃,推荐使用 exec(open("./filename").read())
4. 不相等操作符"<>"被 Python3 废弃,统一使用"!="
5. long 整数类型被 Python3 废弃,统一使用 int
6. xrange 函数被 Python3 废弃,统一使用 range,Python3 中 range 的机制也进行修改并提高
了大数据集生成效率
7. Python3 中这些方法再不再返回 list 对象:dictionary 关联的 keys()、values()、items(),zip(),
map(),filter(),但是可以通过 list 强行转换:
1. mydict={"a":1,"b":2,"c":3}
2. mydict.keys() #<built-in method keys of dict object at 0x000000000040B4C8>
3. list(mydict.keys()) #['a', 'c', 'b']
8. 迭代器 iterator 的 next()函数被 Python3 废弃,统一使用 next(iterator)
9. raw_input 函数被 Python3 废弃,统一使用 input 函数
10. 字典变量的 has_key 函数被 Python 废弃,统一使用 in 关键词
11. file 函数被 Python3 废弃,统一使用 open 来处理文件,可以通过 io.IOBase 检查文件类型
12. apply 函数被 Python3 废弃
13. 异常 StandardError 被 Python3 废弃,统一使用 Exception
修改类差异
1. 浮点数除法操作符“/”和“//”的区别
“ / ”:
Python2:若为两个整形数进行运算,结果为整形,但若两个数中有一个为浮点数,则结果为
浮点数;
Python3:为真除法,运算结果不再根据参加运算的数的类型。
“//”:
Python2:返回小于除法运算结果的最大整数;从类型上讲,与"/"运算符返回类型逻辑一致。
Python3:和 Python2 运算结果一样。
2. 异常抛出和捕捉机制区别
Python2
1. raise IOError, "file error" #抛出异常
2. except NameError, err: #捕捉异常
Python3
1. raise IOError("file error") #抛出异常
2. except NameError as err: #捕捉异常
3. for 循环中变量值区别
Python2,for 循环会修改外部相同名称变量的值
1. i = 1
2. print ('comprehension: ', [i for i in range(5)])
3. print ('after: i =', i ) #i=4
Python3,for 循环不会修改外部相同名称变量的值
1. i = 1
2. print ('comprehension: ', [i for i in range(5)])
3. print ('after: i =', i ) #i=1
㈤ python中xrange和range的区别用法
在python中
range
函数说明:range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个列表。
例子:总结:
所以xrange做循环的性能比range好,尤其是返回很大的时候。尽量用xrange吧,除非你是要返回一个列表。
㈥ Python|range函数用法完全解读
迭代器是 23 种设计模式中最常用的一种(之一),在 Python 中随处可见它的身影,我们经常用到它,但是却不一定意识到它的存在。在关于迭代器的系列文章中(链接见文末),我至少提到了 23 种生成迭代器的方法。有些方法是专门用于生成迭代器的,还有一些方法则是为了解决别的问题而“暗中”使用到迭代器。
在系统学习迭代器之前,我一直以为 range() 方法也是用于生成迭代器的,现在却突然发现,它生成的只是可迭代对象,而并不是迭代器! (PS:Python2 中 range() 生成的是列表,本文基于Python3,生成的是可迭代对象)
于是,我有了这样的疑问:为什么 range() 不生成迭代器呢?在查找答案的过程中,我发现自己对 range 类型的认识存在一些误区。因此,本文将和大家全面地认识一下 range ,期待与你共同学习进步。
1、range() 是什么?
它的语法:range(start, stop [,step]) ;start 指的是计数起始值,默认是 0;stop 指的是计数结束值,但不包括 stop ;step 是步长,默认为 1,不可以为 0 。range() 方法生成一段左闭右开的整数范围。
对于 range() 函数,有几个注意点:(1)它表示的是左闭右开区间;(2)它接收的参数必须是整数,可以是负数,但不能是浮点数等其它类型;(3)它是不可变的序列类型,可以进行判断元素、查找元素、切片等操作,但不能修改元素;(4)它是可迭代对象,却不是迭代器。
2、 为什么range()不生产迭代器?
可以获得迭代器的内置方法很多,例如 zip() 、enumerate()、map()、filter() 和 reversed() 等等,但是像 range() 这样仅仅得到的是可迭代对象的方法就绝无仅有了(若有反例,欢迎告知)。这就是我存在知识误区的地方。
在 for-循环 遍历时,可迭代对象与迭代器的性能是一样的,即它们都是惰性求值的,在空间复杂度与时间复杂度上并无差异。我曾概括过两者的差别是“一同两不同”:相同的是都可惰性迭代,不同的是可迭代对象不支持自遍历(即next()方法),而迭代器本身不支持切片(即 getitem () 方法)。
虽然有这些差别,但很难得出结论说它们哪个更优。现在微妙之处就在于,为什么给 5 种内置方法都设计了迭代器,偏偏给 range() 方法设计的就是可迭代对象呢?把它们都统一起来,不是更好么?
事实上,Pyhton 为了规范性就干过不少这种事,例如,Python2 中有 range() 和 xrange() 两种方法,而 Python3 就干掉了其中一种,还用了“李代桃僵”法。为什么不更规范点,令 range() 生成的是迭代器呢?
关于这个问题,我没找到官方解释,以下纯属个人观点 。
zip() 等方法都需要接收确定的可迭代对象的参数,是对它们的一种再加工的过程,因此也希望马上产出确定的结果来,所以 Python 开发者就设计了这个结果是迭代器。这样还有一个好处,即当作为参数的可迭代对象发生变化的时候,作为结果的迭代器因为是消耗型的,不会被错误地使用。
而 range() 方法就不同了,它接收的参数不是可迭代对象,本身是一种初次加工的过程,所以设计它为可迭代对象,既可以直接使用,也可以用于其它再加工用途。例如,zip() 等方法就完全可以接收 range 类型的参数。
也就是说,range() 方法作为一种初级生产者,它生产的原料本身就有很大用途,早早把它变为迭代器的话,无疑是一种画蛇添足的行为。
对于这种解读,你是否觉得有道理呢?欢迎就这个话题与我探讨。
3、range 类型是什么?
以上是我对“为什么range()不产生迭代器”的一种解答。顺着这个思路,我研究了一下它产生的 range 对象,一研究就发现,这个 range 对象也并不简单。
首先奇怪的一点就是,它竟然是不可变序列!我从未注意过这一点。虽然说,我从未想过修改 range() 的值,但这一不可修改的特性还是令我惊讶。
翻看文档,官方是这样明确划分的——有三种基本的序列类型:列表、元组和范围(range)对象。(There are three basic sequence types: lists, tuples, and range objects.)
这我倒一直没注意,原来 range 类型居然跟列表和元组是一样地位的基础序列!我一直记挂着字符串是不可变的序列类型,不曾想,这里还有一位不可变的序列类型呢。
那 range 序列跟其它序列类型有什么差异呢?
普通序列都支持的操作有 12 种。range 序列只支持其中的 10 种,不支持进行加法拼接与乘法重复。
那么问题来了:同样是不可变序列,为什么字符串和元组就支持上述两种操作,而偏偏 range 序列不支持呢?虽然不能直接修改不可变序列,但我们可以将它们拷贝到新的序列上进行操作啊,为何 range 对象连这都不支持呢?
且看官方文档的解释:
…e to the fact that range objects can only represent sequences that follow a strict pattern and repetition and concatenation will usually violate that pattern.
原因是 range 对象仅仅表示一个遵循着严格模式的序列,而重复与拼接通常会破坏这种模式…
问题的关键就在于 range 序列的 pattern,仔细想想,其实它表示的就是一个等差数列啊(喵,高中数学知识没忘…),拼接两个等差数列,或者重复拼接一个等差数列,想想确实不妥,这就是为啥 range 类型不支持这两个操作的原因了。由此推论,其它修改动作也会破坏等差数列结构,所以统统不给修改就是了。
4、小结
回顾全文,我得到了两个偏冷门的结论:range 是可迭代对象而不是迭代器;range 对象是不可变的等差序列。
若单纯看结论的话,你也许没有感触,或许还会说这没啥了不得啊。但如果我追问,为什么 range 不是迭代器呢,为什么 range 是不可变序列呢?对这俩问题,你是否还能答出个自圆其说的设计思想呢?(PS:我决定了,若有机会面试别人,我必要问这两个问题的嘿~)
由于 range 对象这细微而有意思的特性,我觉得这篇文章写得值了。本文是作为迭代器系列文章的一篇来写的,所以对于迭代器的基础知识介绍不多,另外,还有一种特殊的迭代器也值得单独成文,那就是生成器了。
㈦ python xrange鍦ㄥ摢涓搴挞噷
1. python3娌℃湁xrange锛屽傛灉python2杩佺Щ鍒3銆佹垨钥呰佸悓镞跺湪2/3璺戠▼搴忥纴灏辫佹敞镒忋
2. xrange涓嶆敮鎸佸垏鐗囷纴杩欎釜鐢ㄨ捣𨱒ュ彲鑳戒笉鏄寰堢埥銆
涓浜鸿夊缑锛屽傛灉鏁版嵁閲忎笉澶э纴杩樻槸鐢╮ange锛屽傛灉鏁版嵁澶у苟涓旀槸鐗堟湰2镓嶈冭槛鐢▁range銆
㈧ python xrange怎么倒序循环
其实用range就可以倒循环了,
range(10,0,-1)
从10到0,每次减一。