标签: python-internals

为什么deque实现为链表而不是循环数组?

CPython的deque实现为64项的双向链表大小的"块"(阵列).除了链表两端的那些块外,这些块都是满的.在IIUC中,当pop/ popleft删除块中的最后一项时,块被释放; 当append/ appendleft尝试添加新项目并且相关块已满时,将分配它们.

我理解使用链接列表而不是链接项列表所列出的优点:

  • 减少每个项目中prev和next的指针的内存成本
  • 减少为malloc/ free添加/删除的每个项目执行/的运行时成本
  • 通过将连续指针放在彼此旁边来改善缓存局部性

但是为什么不是首先使用单个动态大小的圆形数组而不是双链表呢?

AFAICT,圆形阵列将保留所有上述优点,并维持(atortized)成本pop*/ append*at O(1)(通过分配,就像在中list).此外,它还可以提高从当前O(n)到索引的索引查找成本O(1).循环数组也可以更简单地实现,因为它可以重用大部分list实现.

我可以在C++这样的语言中看到支持链表的论证,其中可以O(1)使用指针或迭代器从中间删除项目; 但是,python deque没有API来执行此操作.

python cpython python-3.x python-internals

23
推荐指数
2
解决办法
1159
查看次数

"del"究竟做了什么?

这是我的代码:

from memory_profiler import profile

@profile
def mess_with_memory():
    huge_list = range(20000000)
    del huge_list
    print "why this kolaveri di?"
Run Code Online (Sandbox Code Playgroud)

当我从解释器运行时,这就是输出:

Line#Mem使用增量行内容

 3      7.0 MiB      0.0 MiB   @profile
 4                             def mess_with_memory():
 5                             
 6    628.5 MiB    621.5 MiB       huge_list = range(20000000)
 7    476.0 MiB   -152.6 MiB       del huge_list
 8    476.0 MiB      0.0 MiB       print "why this kolaveri di"
Run Code Online (Sandbox Code Playgroud)

如果你注意到输出,创建巨大的列表消耗621.5 MB,而删除它只需释放152.6 MB.当我检查文档时,我发现了以下声明:

the statement del x removes the binding of x from the namespace referenced by the local scope
Run Code Online (Sandbox Code Playgroud)

所以我猜,它并没有删除对象本身,而只是取消绑定它.但是,它在解除绑定方面做了什么呢?它释放了如此多的空间(152.6 MB) …

python memory python-internals

22
推荐指数
1
解决办法
5882
查看次数

print语句如何创建局部变量

问题在这篇文章的最后.

第一个片段:空局部变量字典.

def outer():
    x = 1
    def inner():
        print "Local variables: %s" % locals()
    return inner()
print outer()
Run Code Online (Sandbox Code Playgroud)

输出:局部变量:{}

第二个片段:在inner()函数内打印并创建局部变量条目.

def outer():
    x = 1
    def inner():
        print x
        print "Local variables: %s" % locals()
    return inner()
print outer()
Run Code Online (Sandbox Code Playgroud)

输出:

1
Local variables: {'x': 1}
Run Code Online (Sandbox Code Playgroud)

第三个片段:来自内部函数内部的del x:

def outer():
    x = 1
    def inner():
        print x
        print "Local variables: %s" % locals()
        del x
    return inner()
print outer()
Run Code Online (Sandbox Code Playgroud)

输出:

>>> outer()
Traceback (most recent call last): …
Run Code Online (Sandbox Code Playgroud)

python python-internals

22
推荐指数
2
解决办法
983
查看次数

为什么None是python中最小的?

我从python中学到了什么:

None is frequently used to represent the absence of a value

当我放入一个列表并用数字和字符串排序.我得到了以下结果,这意味着它是最小的数字?

相反:

>>> sorted([1, 2, None, 4.5, (-sys.maxint - 1), (sys.maxint - 1), 'abc'], reverse=True)
['abc', 9223372036854775806, 4.5, 2, 1, -9223372036854775808, None]
>>>
Run Code Online (Sandbox Code Playgroud)

正常排序:

>>> sorted([1, 2, None, 4.5, (-sys.maxint - 1), (sys.maxint - 1), 'abc'])
[None, -9223372036854775808, 1, 2, 4.5, 9223372036854775806, 'abc']
>>>
Run Code Online (Sandbox Code Playgroud)

python排序函数如何使用None?

python python-internals

22
推荐指数
1
解决办法
1319
查看次数

列表查找比元组更快?

在过去,当我需要在紧密循环中使用类似数组的索引查找时,我通常使用元组,因为它们通常看起来非常高效(接近仅使用n个变量).但是,我决定今天质疑这个假设,并得出一些令人惊讶的结果:

In [102]: l = range(1000)
In [103]: t = tuple(range(1000))
In [107]: timeit(lambda : l[500], number = 10000000)
Out[107]: 2.465047836303711
In [108]: timeit(lambda : t[500], number = 10000000)
Out[108]: 2.8896381855010986
Run Code Online (Sandbox Code Playgroud)

元组查找似乎比列表查找长17%!重复实验给出了类似的结果.拆开每个,我发现它们都是:

In [101]: dis.dis(lambda : l[5])
  1           0 LOAD_GLOBAL              0 (l)
              3 LOAD_CONST               1 (5)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE    
Run Code Online (Sandbox Code Playgroud)

作为参考,典型的10,000,000个全局变量查找/返回需要2.2秒.另外,我在没有lambdas的情况下运行它,你知道,以防万一(注意数字= 100,000,000而不是10,000,000).

In [126]: timeit('t[500]', 't=range(1000)', number=100000000)
Out[126]: 6.972800970077515
In [127]: timeit('t[500]', 't=tuple(range(1000))', number=100000000)
Out[127]: 9.411366939544678
Run Code Online (Sandbox Code Playgroud)

在这里,元组查找需要35%的时间.这里发生了什么?对于非常紧密的循环,这实际上似乎是一个显着的差异.可能是什么导致了这个?

注意,对于分解为变量(例如x,y = t),元组稍微快一点(在我的几次测试中减少约6%的时间),并且从固定数量的参数构造,元组疯狂得快(约83%的时间减少) ).不要将这些结果作为一般规则; 我刚刚完成了一些对大多数项目毫无意义的小型项目.

In [169]: print(sys.version)
2.7.1 (r271:86882M, Nov 30 2010, …
Run Code Online (Sandbox Code Playgroud)

python performance tuples list python-internals

21
推荐指数
2
解决办法
3157
查看次数

为什么`float`函数慢于乘以1.0?

我知道这可能被认为是一个非问题,但我为HPC环境编写软件,所以这3.5倍的速度增加实际上有所不同.

In [1]: %timeit 10 / float(98765)            
1000000 loops, best of 3: 313 ns per loop

In [2]: %timeit 10 / (98765 * 1.0)
10000000 loops, best of 3: 80.6 ns per loop
Run Code Online (Sandbox Code Playgroud)

我曾经dis看过代码,我认为它float()会变慢,因为它需要一个函数调用(不幸的是我无法dis.dis(float)看到它实际上在做什么).

我想第二个问题是我float(n)应该何时使用,何时使用n * 1.0

python optimization python-internals

21
推荐指数
1
解决办法
950
查看次数

Python 3.4多处理队列比Pipe更快,意外

我正在做一个从udp套接字接收样本的音频播放器,一切正常.但是当我实现一个丢失隐藏算法时,播放器未能以例外速率继续产生静音(每个10ms发送一个多个160字节的列表).

当用pyaudio播放音频时,使用阻塞调用写入来播放一些样本,我注意到它在样本持续时间内平均被阻止.所以我创建了一个新的专用流程来播放样本.

主进程处理音频输出流,并使用multiprocessing.Pipe将结果发送到该进程.我决定使用multiprocessing.Pipe,因为它应该比其他方式更快.

不幸的是,当我在虚拟机上运行该程序时,比特率是我在快速PC上获得的一半,它没有达到目标比特率.

经过一些测试,我得出结论,造成延迟的原因是Pipe的功能send.

我做了一个简单的基准测试脚本(见下文),以了解传输到流程的各种方法之间的差异.该脚本不断发送[b'\x00'*160]5秒,并计算总共发送字节对象的字节数.我测试了以下发送方法:"不发送",多处理.管道,多处理.Queue,multiprocessing.Manager,multiprocessing.Listener/Client,最后是socket.socket:

我的"快速"PC运行窗口7 x64的结果:

test_empty     :     1516076640
test_pipe      :       58155840
test_queue     :      233946880
test_manager   :        2853440
test_socket    :       55696160
test_named_pipe:       58363040
Run Code Online (Sandbox Code Playgroud)

运行Windows 7 x64的VirtualBox VM guest虚拟机的结果,运行Windows 7 x64的主机:

test_empty     :     1462706080
test_pipe      :       32444160
test_queue     :      204845600
test_manager   :         882560
test_socket    :       20549280
test_named_pipe:       35387840  
Run Code Online (Sandbox Code Playgroud)

使用的脚本:

from multiprocessing import Process, Pipe, Queue, Manager
from multiprocessing.connection import Client, Listener
import time

FS = "{:<15}:{:>15}"


def test_empty():
    s = time.time()
    sent = 0
    while …
Run Code Online (Sandbox Code Playgroud)

python sockets windows python-3.x python-internals

21
推荐指数
1
解决办法
1876
查看次数

如何在python OrderedDict上使用字符串键而不是整数进行切片?

由于OrderedDict具有列表(具有有序元素)和字典(使用键而不是索引)的特征,因此使用键切片似乎很自然.

>>> from collections import OrderedDict
>>> cities = OrderedDict((('san francisco', 650), ('new york', 212), ('shanghai', 8621), ('barcelona', 42423)))
>>> test['shanghai':]  # I want all the cities from shanghai to the end of the list
TypeError: unhashable type
Run Code Online (Sandbox Code Playgroud)

有趣的是,由于OrderedDictionary.__getslice__没有实施,这不是你看到的错误.我尝试添加自己的__getslice__方法OrderedDict,但我一直遇到这个TypeError问题.似乎Python正在进行某种类型检查以强制切片键只是整数,在它们传递给__getslice__函数之前,是多少unpythonic!

>>> class BetterOrderedDict(OrderedDict):
        def __getslice__(self, start=None, end=None, step=1):
            return 'potato'

>>> test = BetterOrderedDict((('one', 1), ('two', 2), ('three', 3), ('four', 4)))
>>> print test[1:4]
'potato'                           # ok this makes sense so …
Run Code Online (Sandbox Code Playgroud)

python dictionary ordereddictionary python-2.7 python-internals

21
推荐指数
2
解决办法
1499
查看次数

为什么排序列表大于未排序列表

我有一个列表my_list(该列表包含utf8字符串):

>>> len(my_list)
8777
>>> getsizeof(my_list)                     #  <-- note the size
77848
Run Code Online (Sandbox Code Playgroud)

出于某种原因,排序列表(my_sorted_list = sorted(my_list))使用更多内存:

>>> len(my_sorted_list)
8777
>>> getsizeof(my_sorted_list)              #  <-- note the size
79104
Run Code Online (Sandbox Code Playgroud)

为什么sorted返回一个列表,在内存中占用的空间比初始未排序列表多?

python sorting list python-3.x python-internals

21
推荐指数
2
解决办法
424
查看次数

python中的eval函数范围

请考虑以下示例:

i=7
j=8
k=10
def test():
    i=1
    j=2
    k=3
    return dict((name,eval(name)) for name in ['i','j','k'])
Run Code Online (Sandbox Code Playgroud)

它返回:

>>> test()
{'i': 7, 'k': 10, 'j': 8}
Run Code Online (Sandbox Code Playgroud)

为什么eval不考虑函数内定义的变量?从文档中,您可以选择传递全局变量和本地字典.这意味着什么?最后,我如何修改这个小案例才能使它工作?

python eval python-internals

20
推荐指数
1
解决办法
890
查看次数