如何复制对象而不引用它?

时间:2012-02-23 13:52:29

标签: python object copy

我不确定我的标题是否适合我正在寻找的内容,但我认为引用是问题所在。

我有一个Reader对象,我可以通过它循环:

msrun = pymzml.run.Reader(mzmlFile)
for feature in msrun:
    print feature['id']

使用此代码,我从msrun中获取所有功能的id,从1开始。但是,我需要首先遍历代码并获取我想要的所有密钥并将它们放在列表中,如下所示:

def getKeys(msrun, excludeList):
    spectrumKeys = []
    done = False
    for spectrum in msrun:
        if done:
            break
        if spectrum['ms level'] == 2:
            for key in spectrum:
                if key not in excludeList and not key.startswith('MS:'): 
                    done = True
                    spectrumKeys.append(key)
            spectrumKeys.extend(spectrum['precursors'][0].keys())
            precursorKeys = spectrum['precursors'][0].keys()
            break
        return spectrumKeys, precursorKeys

但是,如果我要运行此代码:

msrun = pymzml.run.Reader(mzmlFile)
specKeys, precursKeys = getKeys(msrun, ['title','name'])
for feature in msrun:
    print feature['id']

它从未在getKeys()循环中的id开始(它从11开始而不是1)。所以我猜pymzml.run.Reader()就像一个生成器对象。所以我试着复制这个对象。首先我试过

copyMsrun = msrun
specKeys, precursKeys = getKeys(copyMsrun, ['title','name'])

但是如果我理解正确的话会产生同样的问题,因为执行copyMsrun = msrun会使它们指向相同的东西。

然后我试了

import copy
copyMsrun = copy.copy(msrun)

但我仍然遇到同样的问题。我使用copy.copy而不是copy.deepcopy,因为我不认为Reader对象包含其他对象,当我尝试深度复制时,我得到了

TypeError: object.__new__(generator) is not safe, use generator.__new__().

那么如何我复制一个对象,以便循环通过一个对象不会影响另一个对象?我应该做什么

msrun = pymzml.run.Reader(mzmlFile)
copyMsrun = pymzml.run.Reader(mzmlFile)


编辑: 关于Ade YU的评论,我也尝试过,但是当我做的时候

spectrumList = []
for spectrum in msrun:
    print spectrum['id']
    spectrumList.append(spectrum)

for spectrum in spectrumList:
    print spectrum['id']

第一次打印给我1-10,但第二次打印给我十次10。

4 个答案:

答案 0 :(得分:4)

从pymzML和文档的出版,很明显这种“病态设计”是故意的。初始化数千个频谱对象将产生巨大的计算开销,内存和CPU周期,这是根本不需要的。通常,解析大量的mzML会自然地要求分析时解析方法,而不是收集以后需要分析的所有内容。

话虽如此,pymzML仍然提供了简单地通过调用spectrum.deRef()来“深度复制”频谱的功能。使用此功能的优点是在复制之前将剥离所有不必要的数据,因此提供较小的对象。 pymzML deRef

  run = pymzml.run.Reader(file_to_read, MS1_Precision = 5e-6, MSn_Precision = 20e-6)
  for spec in run:
   tmp = spec.deRef()

希望有所帮助。

答案 1 :(得分:2)

看起来你正在处理一个病态设计的课程。您正在使用的库中存在一些严重缺陷,尤其是迭代器反复生成相同对象的部分。

您可能需要复制迭代器的输出,如下所示:

objs = [copy.deepcopy(obj) for obj in pymzml.run.Reader(mzmlFile)]

for obj in objs:
    # do something
for obj in objs:
    # do something

如果这不起作用,你需要找到编写图书馆并没收他们电脑的人。

答案 2 :(得分:2)

尝试itertools.tee,它为您提供独立的迭代器。如果这不起作用,你可能遇到麻烦,因为你的生成器产生的对象取决于某些外部状态,(id =到目前为止产生的对象数量?),并且没有办法自动帮助在那种情况下。 deepcopy是你最好的选择,但是如果这不起作用,你必须编写自己的类来捕获来自spectrum对象的信息。

spectrumList = []
for spectrum in msrun:
    spectrumList.append(MySpectrum(spectrum))

或较短的变体

spectrums =  list(map(MySpectrum(msrun)))

你需要像

这样的东西
class MySpectrum:
    def __init__(self, spectrum):
        self.id = spectrum.id
        ...

答案 3 :(得分:-1)

使用deepcopy模块分配它们而不指向同一个对象

from copy import deepcopy
myq=deepcopy(transq)