Python: как реализовать копирование для базового класса, который работает для унаследованных с новыми атрибутами - PullRequest
0 голосов
/ 28 мая 2018

Как реализовать копию для базового класса, который работает для унаследованных с новыми атрибутами, без реализации __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

Но это не решает проблему в общем случае: для глубокой копии я хотел бы копировать унаследованные атрибуты, а не копировать их, и управлять глубоким копированием для переопределений только при необходимости.

1 Ответ

0 голосов
/ 28 мая 2018

Для вашего примера это сработает - вам «нужно» только переопределить _copyattrs - теперь я не уверен, что это лучше, чем просто переопределить __copy__.

class A(object):
    _copyattrs = ["a"]

    def __copy__(self):
        args = [getattr(self, attrname) for attrname in self._copyattrs]
        return type(self)(*args) 


class B(A):
    _copyattrs = ["c"]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...