多次递归切片 np 数组是否有任何惩罚?

mri*_*rip 5 python numpy

假设我想使用 np 数组作为固定的只读队列并从它的前面弹出。这是一种自然的方法:

def pop(k,q):
    return q[:k],q[k:]
## example usage:
x = np.arange(1000)
for i in range(5):
    a,x = pop(i,x)
    print(a) 
Run Code Online (Sandbox Code Playgroud)

这似乎很好,但我想确保如果q=q[k:]执行数千或数百万次,没有隐藏状态或隐藏引用。似乎没有:取一个切片,np 只是存储一个指向原始数据缓冲区的指针和新索引。但我想确定一下,因为如果我遗漏了什么,我可以将其表示为一个元组 (np.array,index),它不是那么干净:

def pop0(k,q):
    x,i = q
    return x[i:i+k],(x,i+k)
Run Code Online (Sandbox Code Playgroud)

tst*_*isl 1

会很安全的。您可以使用内存分析器包来观察内存使用情况:

对于以下代码:

import numpy as np

@profile
def good_pop():
    def pop(k,q):
        return q[:k],q[k:]
    x = np.arange(10000)
    for i in range(5000):
        a,x = pop(i,x)

@profile
def bad_pop():
    def pop(k,q):
        return q[:k].copy(),q[k:].copy()
    x = np.arange(10000)
    for i in range(5000):
        a,x = pop(i,x)

good_pop()
bad_pop()
Run Code Online (Sandbox Code Playgroud)

使用命令进行分析:

$ python3 -m memory_profiler file.py
Run Code Online (Sandbox Code Playgroud)

产生的结果:

Line #    Mem usage    Increment   Line Contents
================================================
     3   49.023 MiB   49.023 MiB   @profile
     4                             def good_pop():
     5   49.023 MiB    0.000 MiB       def pop(k,q):
     6   49.023 MiB    0.000 MiB           return q[:k],q[k:]
     7   49.023 MiB    0.000 MiB       x = np.arange(10000)
     8   49.023 MiB    0.000 MiB       for i in range(5000):
     9   49.023 MiB    0.000 MiB           a,x = pop(i,x)


Line #    Mem usage    Increment   Line Contents
================================================
    11   49.023 MiB   49.023 MiB   @profile
    12                             def bad_pop():
    13   49.234 MiB    0.000 MiB       def pop(k,q):
    14   49.234 MiB    0.211 MiB           return q[:k].copy(),q[k:].copy()
    15   49.023 MiB    0.000 MiB       x = np.arange(10000)
    16   49.234 MiB    0.000 MiB       for i in range(5000):
    17   49.234 MiB    0.000 MiB           a,x = pop(i,x)
Run Code Online (Sandbox Code Playgroud)

一堆零good_pop()证明了在这个循环中没有创建额外的对象。