Python中的容器列表:标准列表与numpy数组

时间:2012-06-12 19:40:48

标签: python memory-management numpy

我正在编写一些需要存储和访问不同类型元素列表的python代码。此列表的每个元素都具有不同的类类型。例如:

def file_len(fname):
    i = 0
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

element_list = [ ]
data = np.loadtxt(filename)


if file_len(filename) == 1 : 
            data = np.loadtxt(filename)
            param1 = data[0]
            param2 = data[1]
            element_list.append(Class1.Class1(param1,param2))
else:
    for field in data:
                    param1 = field[0]
                    param2 = field[1]
                    element_list.append(Class1.Class1(param1, param2)

稍后我将需要多次访问在element_list上插入的Class1中的方法,但不需要修改列表:

for i in xrange(10000):
    for element in element_list:
        result += element.calculate_result(i).real #the results will be complex

有一种有效的方法吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

这不是一个完整的答案,但我发现了两件我可以贡献的事情。

以下是file_len()的改进版本。如果文件为零长度,则此值将返回0。对于零长度文件,函数返回1,对于包含一行的文件,返回1。

def file_len(fname):
    i = 0
    with open(fname) as f:
        for i, l in enumerate(f, 1):
            pass
    return i

这是一种更快速的计算循环方式。

result = sum(e.calculate_result(i).real for i in xrange(10000) for e in element_list)

使用reduce()可能会更快,但我认为它不会更快。使用reduce()可以节省大量成本,如果您可以反复使用绑定名称,但我们需要绑定名称e,以便即使e.calculate_result(i).real类型也可以调用e可能是任何东西。

如果你能做这样的事情,可能会更快一些。

import itertools as it
import operator as op
result = reduce(op.add, it.imap(SomeClass.calculate_something, it.product(element_list, xrange(10000))))

同样,主要的节省是避免绑定名称。 it.product()会返回包含(e, i)的元组,其中e是来自element_list的元素,而i是来自xrange(10000)的数字。然后it.imap()将调用该函数并将元组作为参数传递。然后reduce()将总结一切。实际上,只是调用sum()可能与reduce(op.add)一样好,但你可以尝试两种方式,看看其中一个是否比另一个略快。如果你能找到SomeClass.calculate_something合理的东西,那么也许你可以做到这一点。

嗯,可能值得尝试让sum()(或reduce())计算一个复数和,然后在总和完成时扔掉虚部。这会比每个值访问一次.real属性更快吗?我不确定,但它可能有助于您使reduce()版本正常工作。

编辑:

您应该尝试在PyPy下运行您的程序。

http://pypy.org/

如果你这样做,请务必使用此行而不是我显示的第一行:

result = sum(e.calculate_result(i).real for e in element_list for i in xrange(10000))

这样,您连续使用每个元素e进行10000次调用,这有助于PyPy即时编译器(“JIT”)生成更好的代码。我不知道JIT是否会帮助只有10000次通话,但看起来这应该是尝试它的方式。

答案 1 :(得分:0)

您可以通过在实例化时传递该视图,将结果放入类中的视图中。如果您更频繁地访问数据而不是调用类方法来更新数据,那么这应该可行。

以下内容......

def file_len(fname):
    i = 0
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

element_list = [ ]
data = np.loadtxt(filename)


array_idx = 0

# length_of_data is the number of elements that will be in element_list
result_array = numpy.zeros(length_of_data, dtype='complex128')

if file_len(filename) == 1 : 
    data = np.loadtxt(filename)
    param1 = data[0]
    param2 = data[1]
    element_list.append(Class1.Class1(param1, param2, 
                            result_array[array_idx:array_idx+1]))
    array_idx += 1
else:
    for field in data:
        param1 = field[0]
        param2 = field[1]
        element_list.append(Class1.Class1(param1, param2,
                            result_array[array_idx:array_idx+1])
        array_idx += 1

在课程中,您可以直接更新视图。考虑这个最小的例子:

import numpy

a = numpy.zeros(5, dtype='complex128')

class Foo(object):

    def __init__(self, real, imag, array_view):
        self._array_view = array_view
        self._array_view[:] = real + 1j*imag #<--- The [:] is needed


element_list = []
for n in range(0, len(a)):
    element_list.append(Foo(n, n+1, a[n:n+1]))

print(a)
print(numpy.sum(a))
相关问题