对象列表中的快速索引/值设置

时间:2014-08-09 23:47:19

标签: python list oop object speech

我正在写一个python包来将语音信号分解成它的频谱谐波,这样它们中的每一个都可以表示为一个复指数。 (非常)简化的代码描述如下:

# -*- coding: utf-8 -*-

import numpy as np

class HarmObj(object):

    # Creates an instance for each harmonic.
    def __init__(self, file_size):
        self.mag = np.zeros((file_size))
        self.phi = np.zeros((file_size))
        self.freq = np.zeros((file_size))

class SignalObj(object):

# Creates an instance for the synthesized speech signal, which is formed by the
# harmonics.
    def __init__(self, n_harm, file_size):
        self.n_harm = n_harm
        self.size = file_size
        self.harmonics = [HarmObj(self.size) for i in xrange(self.n_harm)]

    def update_values(self, a, freq, frame):
        for harmonic in xrange(self.n_harm):
            self.harmonics[harmonic].mag[frame] = np.abs(a[harmonic])
            self.harmonics[harmonic].phi[frame] = np.angle(a[harmonic])
            self.harmonics[harmonic].freq[frame] = freq[harmonic]

n_harm = 25
file_size = 100

signal = SignalObj(n_harm, file_size)

for frame in xrange(file_size):

    #Nevermind this part, is just a simplification ;)
    #----------------------------------------------
    real_part = np.random.normal(0.0, 0.9, n_harm)
    imag_part = np.random.normal(0.0, 0.9, n_harm)
    a = real_part + 1j*imag_part
    freq = np.random.normal(500.0, 200.0, n_harm)
    #-----------------------------------------------

    signal.update_values(a, freq, frame)

此脚本运行没有问题。然而,由于在语音信号中谐波和帧的数量可能很大,由于for方法内的SignalObj.update_values循环,代码在某种程度上会在计算上造成负担。

我相信一个" numpy-array"解决方案如

    def update_values(self, a, freq, frame):
        self.harmonics[:].mag[frame] = np.abs(a[:])
        self.harmonics[:].phi[frame] = np.angle(a[:])
        self.harmonics[:].freq[frame] = freq[:]

会更快。但上面的代码并不适用于对象列表。 所以,我想知道是否有办法改变列表属性或创建我自己的结构,然后允许上述优化的值设置过程。

PS。 :顺便提一下,避免此问题的一种可能解决方案是放弃HarmObj类并将magphifreq属性直接关联到SignalObj },即

class SignalObj(object):

    def __init__(self, n_harm, file_size):
        self.n_harm = n_harm
        self.size = file_size
        self.mag = np.zeros((n_harm, file_size))
        self.phi = np.zeros((n_harm, file_size))
        self.freq = np.zeros((n_harm, file_size))

    def update_values(self, a, freq, frame):
        self.mag[:, frame] = np.abs(a[:])
        self.phi[:, frame] = np.angle(a[:])
        self.freq[:, frame] = freq[:]

我在MATLAB版本中采用了这种解决方法,确实更快。但是,由于Python更有资源,我想知道是否有更优雅和pythonic的方式来完成这项工作;)。此外,保持HarmObj实例分开将在以后开始操作时帮助我。

1 个答案:

答案 0 :(得分:0)

由于您用于创建self.harmonics

的方法,此代码存在一些错误

这里简单说明了为什么会出现问题

class Foo()
    __init__(self, foo):
        self.foo = foo

foo = Foo('foo')
bar = [foo] * 3
for i in bar:
    print i.foo

这会返回。

foo
foo
foo

看起来很好......除了它没有,因为它们都指向同一个foo对象。所以

bar[0].foo = 'bar'
for i in bar:
    print i.foo

返回:

bar
bar 
bar

改为使用列表理解。

bar = [Foo('foo') for i in range(3)]
for i in bar:
   print i.foo
bar[0].foo = 'bar'
for i in bar:
   print i.foo

这给出了所需的

foo
foo
foo
bar
foo
foo

对列表进行快速操作,您也可以列出理解。

def update_harmonic(harmonic):
    real_part = np.random.normal(0.0, 0.9, n_harm)
    imag_part = np.random.normal(0.0, 0.9, n_harm)
    a = real_part + 1j*imag_part
    freq = np.random.normal(500.0, 200.0, n_harm)
    signal.update_values(a, freq, frame)

self.harmonics = [x.update_harmonic() for x in self.harmonics]