Генератор методов, копирование и копирование - PullRequest
1 голос
/ 18 июня 2011

Я пытаюсь избежать использования Deepcopy в пользовательском классе (класс Graph)

Графики имеют несколько атрибутов, таких как вершины, ребра и т. Д., И несколько методов-генераторов (методы с * 1003).*).

Мне нужно скопировать график: например, H = deepcopy(G), но не использовать глубокую копию для ускорения программы.

Затем:

  • Если я не использую deepcopy, то методы генератора в новом графе H не получают текущее состояние методов генератора в графе G.

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

Решением было попытаться deepcopy некоторых конкретных методов генератора,но я получаю ошибки.

Кажется, что генераторы сохраняют ссылки, например, вершины и ребра G, а затем при глубокой копировании в H генераторы в H все еще ссылаются на атрибуты G (звучит логично).

Итак, я обречен на использование deepcopy в конце концов или не использовать методы генератора?

Есть ли третий питонический способ?

1 Ответ

2 голосов
/ 18 июня 2011

Я почти уверен, что понимаю, к чему вы клоните. Вот простой пример:

class Graph:
    def __init__(self, nodes):
        self.nodes = list(nodes)
        self.nodegen = self.iternodes()
    def iternodes(self):
        for node in self.nodes:
            yield node
    def copy(self):
        return Graph(self.nodes)

G = Graph([1, 2, 3, 4])
print G.nodegen.next()
H = G.copy()
print H.nodegen.next()
print G.nodegen.next()

Теперь, конечно, это напечатает 1 1 2. Однако вы хотите, чтобы H.nodegen запомнил состояние G.nodegen, чтобы при вызове H.nodegen.next() печаталось 2. Простой способ - сделать их одним и тем же объектом:

class Graph:
    def __init__(self, nodes, nodegen=None):
        self.nodes = list(nodes)
        self.nodegen = self.iternodes() if nodegen is None else nodegen
    def iternodes(self):
        for node in self.nodes:
            yield node
    def copy(self):
        return Graph(self.nodes, self.nodegen)

Это напечатает 1 2 3, так как вызов H.nodegen.next() также продвинет G.nodegen. Если это не то, что вы хотите, мне кажется, что я могу сохранить внутренний счетчик, например:

class Graph:
    def __init__(self, nodes, jnode=0):
        self.nodes = list(nodes)
        self.nodegen = self.iternodes()
        self.jnode = jnode
    def iternodes(self):
        while self.jnode < len(self.nodes):
            self.jnode += 1
            yield self.nodes[self.jnode-1]
    def copy(self):
        return Graph(self.nodes, self.jnode)

Это напечатает 1 2 2, что я подозреваю, что вы хотите. Конечно, вам придется изменить то, как вы заботитесь о таких вещах, как аннулирование итераторов, когда вы меняете self.nodes, но я думаю, что это должно быть довольно просто.

...