Как скопировать объект, не ссылаясь на него? - PullRequest
2 голосов
/ 23 февраля 2012

Я не уверен, что мой заголовок правильный для того, что я ищу, но я думаю, что ссылка - это проблема.

У меня есть объект Reader, с помощью которого я могу выполнить цикл:

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

С этим кодом я получаю идентификаторы, начиная с 1, всех функций в msrun. Однако мне нужно сначала пройтись по коду и получить все нужные мне ключи и поместить их в список, например:

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 () (он начинается с 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)


Edit: Что касается комментария Ade YU, я тоже это попробовал, но когда я делаю

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

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

Первый отпечаток дает мне 1-10, а второй - 10 раз 10

Ответы [ 4 ]

4 голосов
/ 06 марта 2012

Из публикации pymzML и документации становится ясно, что этот «патологический дизайн» сделан специально.Инициализация тысяч объектов спектра создаст огромные вычислительные затраты, память и цикл процессора, которые просто не нужны.Обычно анализ больших наборов 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()

Надеюсь, это поможет.

2 голосов
/ 23 февраля 2012

Похоже, вы имеете дело с патологически разработанным классом.В используемой вами библиотеке есть некоторые серьезные недостатки, особенно в части, где итератор выдает один и тот же объект снова и снова.

Возможно, вам потребуется скопировать выходные данные итератора, например так:1003 *

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

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

Если это не сработает, вам нужно найти того, кто написал библиотеку, и конфисковать их компьютер.

2 голосов
/ 23 февраля 2012

Попробуйте 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
        ...
0 голосов
/ 23 февраля 2012

Используйте модуль deepcopy , чтобы назначать их, не указывая на один и тот же объект

from copy import deepcopy
myq=deepcopy(transq)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...