列表理解 assignment/comparison 在 256 之后失败
List comprehension assignment/comparison fails after 256
我试图找到列表的切片分配和常规分配之间的性能差异。这是代码:
import time
N = 1000
a = list(range(N))
b = list(range(N))
time1 = time.time()
for i in range(N):
a = [x for x in a if x is not i]
time2 = time.time()
for i in range(N):
b[:] = [x for x in b if x is not i]
time3 = time.time()
print a
print b
print time2 - time1
print time3 - time2
我的期望是,对于每个列表 a
和 b
,这将一次删除一个元素,因此 print a
和 print b
都打印为空列出。相反,他们似乎总是打印起始列表,但缺少前 256
个元素。
他们都打印:
[257, 258, 259 ... N-1]
发生了什么事?
我正在使用 Python 2.7.6.
问题是您使用的是 is
而不是 ==
。
前者检查对象身份,而不是相等性。没有理由相信评估 300+1
两次会给你相同的 int
对象,只是它们都会给你 int
个值为 301
的对象.
对于最大 256 的数字,"work" 会发生这种情况,因为您的特定 Python 实现 * 恰好对最大 256 的整数进行实习。在启动时,它为数字 1
创建一个单例对象,为 2
创建一个单例对象,依此类推。任何时候表达式的计算结果为数字 1
,它都会为您提供该对象,而不是新对象。**
不用说,你不应该依赖那个优化。
* IIRC,从 1.x 天到 3.5 的每个版本的 CPython 默认为从 -5 到 256 的所有整数的这种行为,但你可以改变这些在构建时限制或关闭该功能,不同的实现可能会做一些不同的事情。
** 如果您想知道这在 CPython 中是如何工作的,在 C API 级别,PyLong_FromLong
does this by looking up numbers from -5 to 256 in an array of singleton values. You can see the 3.4 version of the code, for example, here;宏 CHECK_SMALL_INT
和它调用的实际函数 get_small_int
以及函数使用的静态数组都在同一个文件中,靠近顶部。
我试图找到列表的切片分配和常规分配之间的性能差异。这是代码:
import time
N = 1000
a = list(range(N))
b = list(range(N))
time1 = time.time()
for i in range(N):
a = [x for x in a if x is not i]
time2 = time.time()
for i in range(N):
b[:] = [x for x in b if x is not i]
time3 = time.time()
print a
print b
print time2 - time1
print time3 - time2
我的期望是,对于每个列表 a
和 b
,这将一次删除一个元素,因此 print a
和 print b
都打印为空列出。相反,他们似乎总是打印起始列表,但缺少前 256
个元素。
他们都打印:
[257, 258, 259 ... N-1]
发生了什么事?
我正在使用 Python 2.7.6.
问题是您使用的是 is
而不是 ==
。
前者检查对象身份,而不是相等性。没有理由相信评估 300+1
两次会给你相同的 int
对象,只是它们都会给你 int
个值为 301
的对象.
对于最大 256 的数字,"work" 会发生这种情况,因为您的特定 Python 实现 * 恰好对最大 256 的整数进行实习。在启动时,它为数字 1
创建一个单例对象,为 2
创建一个单例对象,依此类推。任何时候表达式的计算结果为数字 1
,它都会为您提供该对象,而不是新对象。**
不用说,你不应该依赖那个优化。
* IIRC,从 1.x 天到 3.5 的每个版本的 CPython 默认为从 -5 到 256 的所有整数的这种行为,但你可以改变这些在构建时限制或关闭该功能,不同的实现可能会做一些不同的事情。
** 如果您想知道这在 CPython 中是如何工作的,在 C API 级别,PyLong_FromLong
does this by looking up numbers from -5 to 256 in an array of singleton values. You can see the 3.4 version of the code, for example, here;宏 CHECK_SMALL_INT
和它调用的实际函数 get_small_int
以及函数使用的静态数组都在同一个文件中,靠近顶部。