For... in ... 是不是真的很慢啊?

4 views
Skip to first unread message

oliveagle

unread,
Jan 6, 2009, 12:04:06 PM1/6/09
to python-cn`CPyUG`华蟒用户组
在学习Design Pattern,看到Iterator时突发奇想的把Iterator和内建的For ... in ...做了下性能比较。结果
吓了一跳。
Iterator 的性能非常好,而For...in...却随着List的数据量增加性能直线下降。
我功力尚浅,不知道是不是代码不太好才造成这样的结果。

#!/usr/bin/env python
#coding=utf-8

class VP:
name = ""
division = ""

def __init__(self,n,d):
self.name = n
self.division = d

def getName(self): return self.name
def __str__(self): return "Name: %s Division: %s"%
(self.name,self.division)

class Division:
name = ""
vps = []

def __init__(self, n): self.name = n
def getName(self): return self.name
def addVP(self,n): self.vps.append(VP(n,self.name))
def iterator(self): return DivisionIterator(self.vps)

class Iterator:
data = []
location = 0
length = 0

def __init__(self,d):
self.data = d
self.length = len(self.data)

def next(self):
nt = self.data[self.location]
self.location+=1
return nt
def hasNext(self):
if self.location < self.length and self.data[self.location]!
=None:
return True
else:
return False
def remove(self): pass

class DivisionIterator(Iterator):
def __init__(self,vps):
Iterator.__init__(self, vps)


#------------------------------------------------------------------
# Test

division = Division("Sales")
division.addVP("Ted")
division.addVP("Bob")
division.addVP("Carol")
division.addVP("Alice")

for i in range(1000):
division.addVP(str(i))


iterator = division.iterator()

def ourIterator():
while(iterator.hasNext()):
vp = iterator.next()
#print vp
pass

ourIterator()
#-------------------------------------------------------------------------
#和内建的方式做性能比较

def buildinFor():
for vp in division.vps:
#print vp
pass


buildinFor()


from timeit import Timer
t = Timer("ourIterator()","from __main__ import ourIterator")
print "ourIterator:\t",min(t.repeat())

t = Timer("buildinFor()","from __main__ import buildinFor")
print "buildinFor:\t",min(t.repeat())


结果:
ourIterator: 1.42372529755
buildinFor: 37.8318719343

Heroboy

unread,
Jan 6, 2009, 2:29:15 PM1/6/09
to pyth...@googlegroups.com
你的iterator用之前没有reset

2009/1/7 oliveagle <oliv...@gmail.com>

oliveagle

unread,
Jan 6, 2009, 3:45:13 PM1/6/09
to python-cn`CPyUG`华蟒用户组

恩,Timeit的代码是后便随便添上去的,没注意这个问题。要改成这样是吧。
def ourIterator():
iterator = division.iterator()
while(iterator.hasNext()):
vp = iterator.next()
#print vp
pass
或者在DivisionIterator里添加一个reset(),然后在while前调用。

不过这样做对Iterator测试就很不公平了。我就想嘛,Iterator多了那么多代码怎么可能快成那个样子啊。



On 1月6日, 下午2时29分, Heroboy <yangwei...@gmail.com> wrote:
> 你的iterator用之前没有reset
>
> 2009/1/7 oliveagle <olivea...@gmail.com>
> > buildinFor: 37.8318719343- 隐藏被引用文字 -
>
> - 显示引用的文字 -

limodou

unread,
Jan 6, 2009, 7:21:54 PM1/6/09
to pyth...@googlegroups.com
2009/1/7 oliveagle <oliv...@gmail.com>:

>
>
> 恩,Timeit的代码是后便随便添上去的,没注意这个问题。要改成这样是吧。
> def ourIterator():
> iterator = division.iterator()
> while(iterator.hasNext()):
> vp = iterator.next()
> #print vp
> pass
> 或者在DivisionIterator里添加一个reset(),然后在while前调用。
>
> 不过这样做对Iterator测试就很不公平了。我就想嘛,Iterator多了那么多代码怎么可能快成那个样子啊。
>

把range改为xrange。xrange就是一个迭代方式的,而range会一次性在内存中生成列表,所以会慢。好象从2.6还是多少版本range就是使用xrange替代了。


--
I like python!
UliPad <<The Python Editor>>: http://code.google.com/p/ulipad/
UliWeb <<simple web framework>>: http://uliwebproject.appspot.com
My Blog: (new)http://http://hi.baidu.com/limodou
(old)http://www.donews.net/limodou

风向标

unread,
Jan 7, 2009, 4:21:53 AM1/7/09
to pyth...@googlegroups.com
借地方问下limodou兄呢。
 
range所能生成的列表仅为整形,当我需要生成长整形时就没办法了。
 
除了自己写个,有内置的长整型列表生成函数么?

Heroboy

unread,
Jan 7, 2009, 4:24:16 AM1/7/09
to pyth...@googlegroups.com
range所能生成的列表仅为整形,
当我需要生成长整形时就没办法了。

不是可以的啊
range(2**100,2**100+10)

2009/1/7 风向标 <vane...@gmail.com>

limodou

unread,
Jan 7, 2009, 4:27:07 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 Heroboy <yangw...@gmail.com>:
>> range所能生成的列表仅为整形,
>> 当我需要生成长整形时就没办法了。
>
> 不是可以的啊
> range(2**100,2**100+10)
>

只有一个数试试,好象不行,如:

>>> range(10000000000)
Traceback (most recent call last):
File "<input>", line 1, in <module>
OverflowError: range() result has too many items

不知道有没有,没用过很大的。

Heroboy

unread,
Jan 7, 2009, 4:30:14 AM1/7/09
to pyth...@googlegroups.com
>>> range(10000000000)
10000000000 大约是2的33次方,64位的机器,然后塞满内存应该可以
2009/1/7 limodou <lim...@gmail.com>

limodou

unread,
Jan 7, 2009, 4:32:36 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 Heroboy <yangw...@gmail.com>:

>> >>> range(10000000000)
>
> 10000000000 大约是2的33次方,64位的机器,然后塞满内存应该可以

我这里是报错了,我用的是32位的。我是随便试的,好象是不能太大的数。看到itertools模块有一个count函数:

count( [n])

Make an iterator that returns consecutive integers starting with n. If
not specified n defaults to zero. Does not currently support python
long integers. Often used as an argument to imap() to generate
consecutive data points. Also, used with izip() to add sequence
numbers. Equivalent to:

def count(n=0):
while True:
yield n
n += 1

Note, count() does not check for overflow and will return negative
numbers after exceeding sys.maxint. This behavior may change in the
future.

可以考虑用它,或自已照着写一个。

Leo Jay

unread,
Jan 7, 2009, 4:33:07 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 limodou <lim...@gmail.com>:

> 2009/1/7 Heroboy <yangw...@gmail.com>:
>>> range所能生成的列表仅为整形,
>>> 当我需要生成长整形时就没办法了。
>>
>> 不是可以的啊
>> range(2**100,2**100+10)
>>
>
> 只有一个数试试,好象不行,如:
>
>>>> range(10000000000)
> Traceback (most recent call last):
> File "<input>", line 1, in <module>
> OverflowError: range() result has too many items
>
> 不知道有没有,没用过很大的。
>

大哥,这可是100亿个整数啊。就算是4字节一个整数,那也是40个G的数据量呢。


--
Best Regards,
Leo Jay

limodou

unread,
Jan 7, 2009, 4:35:03 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 Leo Jay <python...@gmail.com>:

很大吗?python直接支持大数运算的:

>>> 10000000000 * 10000000000
100000000000000000000L

不过对于range()或xrange()可能是有限制的。

Heroboy

unread,
Jan 7, 2009, 4:37:49 AM1/7/09
to pyth...@googlegroups.com
xrange没限制,range的话取决于你的内存大小和地址总线的位数

2009/1/7 limodou <lim...@gmail.com>

Leo Jay

unread,
Jan 7, 2009, 4:40:38 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 limodou <lim...@gmail.com>:

> 2009/1/7 Leo Jay <python...@gmail.com>:
>> 2009/1/7 limodou <lim...@gmail.com>:
>>> 2009/1/7 Heroboy <yangw...@gmail.com>:
>>>>> range所能生成的列表仅为整形,
>>>>> 当我需要生成长整形时就没办法了。
>>>>
>>>> 不是可以的啊
>>>> range(2**100,2**100+10)
>>>>
>>>
>>> 只有一个数试试,好象不行,如:
>>>
>>>>>> range(10000000000)
>>> Traceback (most recent call last):
>>> File "<input>", line 1, in <module>
>>> OverflowError: range() result has too many items
>>>
>>> 不知道有没有,没用过很大的。
>>>
>>
>> 大哥,这可是100亿个整数啊。就算是4字节一个整数,那也是40个G的数据量呢。
>>
>
> 很大吗?python直接支持大数运算的:
>
> >>> 10000000000 * 10000000000
> 100000000000000000000L
>
> 不过对于range()或xrange()可能是有限制的。
>

我知道python直接大数运算,但range(n)会生成一个长度为n的list,这个list如果有100亿个整数,一般的机器哪放得下啊。

limodou

unread,
Jan 7, 2009, 4:43:43 AM1/7/09
to pyth...@googlegroups.com

因为我使用了xrange也是不行:

>>> for x in xrange(10000000000):
... if x > 10:
... break
... print x
...


Traceback (most recent call last):
File "<input>", line 1, in <module>

OverflowError: long int too large to convert to int

Leo Jay

unread,
Jan 7, 2009, 4:48:16 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 limodou <lim...@gmail.com>:
> 2009/1/7 Leo Jay <python...@gmail.com>:
>>
>> 我知道python直接大数运算,但range(n)会生成一个长度为n的list,这个list如果有100亿个整数,一般的机器哪放得下啊。
>>
>
> 因为我使用了xrange也是不行:
>
> >>> for x in xrange(10000000000):
> ... if x > 10:
> ... break
> ... print x
> ...
> Traceback (most recent call last):
> File "<input>", line 1, in <module>
> OverflowError: long int too large to convert to int
>

2.6里可以:
>>> for i in xrange(2*100):
... if i > 10: break
... print i
...
0
1
2
3
4
5
6
7
8
9
10

limodou

unread,
Jan 7, 2009, 4:50:42 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 Leo Jay <python...@gmail.com>:

哦,我用的是2.5.

闲云无心

unread,
Jan 7, 2009, 4:56:26 AM1/7/09
to pyth...@googlegroups.com
//2.5
typedef struct {
    PyObject_HEAD
    long    start;
    long    step;
    long    len;
} rangeobject;
//3.0
typedef struct {
    PyObject_HEAD
    PyObject *start;
    PyObject *stop;
    PyObject *step;
} rangeobject;
看来2.5超过long只能自己实现迭代了

wwwjfy

unread,
Jan 7, 2009, 5:45:59 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 Leo Jay <python...@gmail.com>
这是2*100,才200,当然没问题...
--
wwwjfy

Heroboy

unread,
Jan 7, 2009, 5:53:00 AM1/7/09
to pyth...@googlegroups.com
这是2*100,才200,当然没问题...
看来xrange为了速度,内部没有使用python的整形啊。
2009/1/7 wwwjfy <www...@gmail.com>

Leo Jay

unread,
Jan 7, 2009, 6:00:09 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 wwwjfy <www...@gmail.com>:
> 2009/1/7 Leo Jay <python...@gmail.com>
>>
>>
>> 2.6里可以:
>> >>> for i in xrange(2*100):
>> ... if i > 10: break
>> ... print i
>> ...
>> 0
>> 1
>> 2
>> 3
>> 4
>> 5
>> 6
>> 7
>> 8
>> 9
>> 10
>
>
> 这是2*100,才200,当然没问题...
>

靠,丢人了。。。
2.6里也不行。。。

Jiahua Huang

unread,
Jan 7, 2009, 7:09:11 AM1/7/09
to pyth...@googlegroups.com
2009/1/7 Leo Jay <python...@gmail.com>:
> 靠,丢人了。。。
> 2.6里也不行。。。
>

3.0 的 range 可以,
2.5,2.6 的 xrange 和 range 都是 long 不可以

嗯,3.0 里的 int 就是超长整数了

$ python3.0
Python 3.0b3 (r30b3:65927, Sep 14 2008, 01:05:23)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(2**100)
range(0, 1267650600228229401496703205376)
>>>


$ python2.5
Python 2.5.2 (r252:60911, May 7 2008, 15:19:09)
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> xrange(2**100)


Traceback (most recent call last):

File "<stdin>", line 1, in <module>


OverflowError: long int too large to convert to int

>>> range(2**100)


Traceback (most recent call last):

File "<stdin>", line 1, in <module>


OverflowError: range() result has too many items
>>>


$ python2.6
Python 2.6 (r26:66714, Oct 21 2008, 21:50:32)
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> xrange(2**100)


Traceback (most recent call last):

File "<stdin>", line 1, in <module>


OverflowError: long int too large to convert to int

>>> range(2**100)


Traceback (most recent call last):

File "<stdin>", line 1, in <module>

karlos

unread,
Jan 7, 2009, 8:16:40 AM1/7/09
to pyth...@googlegroups.com

刘鑫

unread,
Jan 7, 2009, 8:20:41 AM1/7/09
to pyth...@googlegroups.com
警告一次,不要再发无关的东西出来了。




--
杀人放火金腰带,补路修桥无尸骸。

……

劉鑫
March.Liu
Reply all
Reply to author
Forward
0 new messages