Есть ли способ переопределить метод __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_
Он выглядит действительным, но создание 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):
вместо этого (правильно документирована)
copy_
в конце, и созданиеset
to_be_copied
сделало бы работу быстрее, когда есть много атрибутов.return
заявление было ошибкой.