Как реализовать копию для базового класса, который работает для унаследованных с новыми атрибутами, без реализации __copy__
для унаследованного класса (подразумевая тупую копию для новых атрибутов)?
Т.е. у нас есть класс с одним пользователем-определено и одно вычисленное (или внешняя ссылка, не должна копироваться) поле.Таким образом, копия должна создавать экземпляр, основываясь только на пользовательском поле:
class A(object):
def __init__(self, a):
self.a = a
self.b = a+1
def __copy__(self):
return A(self.a)
В этот момент copy
работает нормально.
Затем мы вводим унаследованный класс, и его конструктор вычисляет аргументы дляБазовый конструктор, основанный на его собственных аргументах, а также вводит новое поле, поэтому сигнатура унаследованного конструктора для базового класса совершенно иная (общая):
class B(A):
def __init__(self, c):
A.__init__(self, c+100)
self.c=c
На данный момент copy
, очевидно, не работаетхорошо, возвращая A
экземпляр.Конечно, мы можем реализовать собственный __copy__
для унаследованного класса, но это крайне неудобно, когда мы вводим некоторые атрибуты, которые следует копировать обычным способом.Итак, чего я хотел бы добиться, так это скопировать «часть» унаследованного класса B на A.__copy__
, но остается стандартным копированием, без повторной реализации __copy__
для всех унаследованных классов.Так есть ли «шаблон дизайна» для таких ситуаций?
UPD: я бы хотел переформулировать пример с copy
на deepcopy
, что более близко к реальному случаю.Таким образом, идея та же - мы должны управлять глубоким копированием класса A, который содержит ссылку, которую не следует копировать глубоко (т. Е. Ссылку на контейнер, в котором содержится объект).Но мы не хотим управлять глубоким копированием унаследованных классов.
from copy import deepcopy
class A:
def __init__(self, content, container):
self.content = content
self.container = container
def __deepcopy__(self, memo):
return A(deepcopy(self.content, memo), self.container)
class B(A):
def __init__(self, attr):
A.__init__(self, [1,2,3], self)
self.attr = attr
b = B(123)
b1=deepcopy(b) # wrong!
Похоже, я нашел шаблон, который подходит в моем конкретном случае (thx @mhawke): сначала скопируйте все, а затем только необходимую глубокую копиюfields.
class A:
def __deepcopy__(self, memo):
o = copy(self)
o.content = deepcopy(self.content)
return o
Но это не решает проблему в общем случае: для глубокой копии я хотел бы копировать унаследованные атрибуты, а не копировать их, и управлять глубоким копированием для переопределений только при необходимости.