Deepcopy специфические атрибуты

1

Есть ли способ переопределить метод __copy__ для класса таким образом, что некоторые атрибуты копируются только как ссылка, а другие атрибуты фактически копируются?

Чтобы уточнить, что я имею в виду, здесь я догадываюсь, как это можно сделать. Рассмотрим класс Spam:

class Spam:
    def __init__(self, val=0, val2=0):
        self.eggs = []
        self.foo = []
        self.val = val
        self.val2 = val2

Предположим, мы хотели удостовериться, что после вызова copy.copy (то есть мелкой копии) в Spam объекте его атрибут eggs был глубоко скопирован в новый объект (так что мутации к атрибуту исходного объекта не изменяют копию eggs). "Почему бы вам просто не deepcopy весь объект?" - потому что, в отличие от eggs, мы хотим, чтобы атрибут foo был скопирован как ссылка (чтобы изменения в нем были видны для всех копий).

Тогда будет ли справедливым подход?

    to_be_copied = ['eggs']  # States which attributes are to be copied

    def __copy__(self):
        copy_ = Spam()

        for attr in self.__dict__:
            if attr in Spam.to_be_copied:
                # Make an actual copy of the attribute
                copy_.__dict__[attr] = copy.copy(self.__dict__[attr])  
            else:
                # Copy reference
                copy_.__dict__[attr] = self.__dict__[attr]

        return copy_
  • 1
    это было бы, если бы вы вернули copy_ в конце, и создание set to_be_copied сделало бы работу быстрее, когда есть много атрибутов.
  • 0
    @Jean-FrançoisFabre Жан-Франсуа Спасибо за то, что указал на это! Отсутствующее return заявление было ошибкой.
Теги:
oop
copy

1 ответ

1
Лучший ответ

Он выглядит действительным, но создание set to_be_copied работу, когда будет много атрибутов.

Кроме того, сократите тройное выражение + список, как показано ниже

to_be_copied = {'eggs'}  # States which attributes are to be copied

def __copy__(self):
    copy_ = Spam()
    copy_.__dict__ = {attr:copy.copy(self.__dict__[attr]) if attr in Spam.to_be_copied else self.__dict__[attr] for attr in self.__dict__}
    return copy_

Недостатком метода __copy__ dunder является то, что он не соответствует принципу наименьшего удивления: пользователи copy.copy ожидают мелкой копии, когда они имеют дело с известными объектами, такими как list, вы предоставляете собственную копию.

Возможно, было бы лучше определить функцию def copy(self): вместо этого (правильно документирована)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню