Python 如何在不引用对象的情况下复制对象?

Python 如何在不引用对象的情况下复制对象?,python,object,copy,Python,Object,Copy,我不确定我的标题是否正确,但我认为引用是问题所在 我有一个读卡器对象,通过它我可以循环: msrun = pymzml.run.Reader(mzmlFile) for feature in msrun: print feature['id'] 通过这段代码,我得到了msrun中所有特性的id,从1开始。但是,我需要首先循环代码,获取我想要的所有密钥并将它们放入列表中,如下所示: def getKeys(msrun, excludeList): spectrumKeys = [

我不确定我的标题是否正确,但我认为引用是问题所在

我有一个读卡器对象,通过它我可以循环:

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
objs = [copy.deepcopy(obj) for obj in pymzml.run.Reader(mzmlFile)]

for obj in objs:
    # do something
for obj in objs:
    # do something
但是,如果我要运行以下代码:

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对象不包含其他对象,当我尝试deepcopy时,我得到了

TypeError: object.__new__(generator) is not safe, use generator.__new__().
那么,我如何复制一个对象,使循环通过一个对象不会影响另一个对象呢?我该怎么办

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


编辑: 在艾德·余的评论中,我也尝试过,但当我这么做的时候

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

for spectrum in spectrumList:
    print spectrum['id']
第一次打印的结果是1-10,但第二次打印的结果是10乘以10。使用模块分配它们,而不指向同一对象

from copy import deepcopy
myq=deepcopy(transq)

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

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

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
objs = [copy.deepcopy(obj) for obj in pymzml.run.Reader(mzmlFile)]

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

如果这不起作用,您需要找到编写该库的人并没收他们的计算机。

试试
itertools.tee
,它为您提供独立的迭代器。如果这不起作用,您可能会遇到麻烦,因为生成器生成的对象依赖于某些外部状态(
id
=到目前为止生成的对象数?),在这种情况下无法自动提供帮助
deepcopy
是您的最佳选择,但如果这不起作用,您必须编写自己的类来捕获
光谱
对象中的所有信息

spectrumList = []
for spectrum in msrun:
    spectrumList.append(MySpectrum(spectrum))
还是较短的变体

spectrums =  list(map(MySpectrum(msrun)))
你需要像这样的东西

class MySpectrum:
    def __init__(self, spectrum):
        self.id = spectrum.id
        ...

从pymzML的出版和文档中可以清楚地看出,这种“病理学设计”是故意的。初始化数千个spectrum对象将产生巨大的计算开销、内存和cpu周期,而这些根本不需要。通常,解析大型mzML集自然需要在解析方法时进行分析,而不是收集稍后需要分析的所有内容

尽管如此,pymzML仍然提供了通过调用spectrum.deRef()来“深度复制”频谱的功能。使用此功能的优点是,在复制之前,所有不必要的数据都将被剥离,从而提供更小的对象


希望这会有所帮助。

您可以在第一个循环中选择所需的信息,并将其存储在一些基本数据结构中,您可以轻松地进行操作。正如我在文章中所述,我的对象中没有对象,deepcopy会出错。这确实有效,但比msrun=pymzml.run.Reader(mzmlFile)慢得多copyMsrun=pymzml.run.Reader(mzmlFile)for copyMsrun中的obj:#在msrun中为obj做点什么:#做点什么,所以我正在使用它。谢谢你的答案,为了简单起见,我将按照我对迪特里希答案的评论方式来做。