Как переопределить copy/deepcopy операции для объекта Python?

Я понимаю различие между copy по сравнению с. deepcopy в модуле копии. Я использовал copy.copy и copy.deepcopy прежде успешно, но это - первый раз, когда я на самом деле пошел о перегрузке __copy__ и __deepcopy__ методы. Я уже Погуглил вокруг и просмотрел встроенные модули Python для поиска экземпляров __copy__ и __deepcopy__ функции (например. sets.py, decimal.py, и fractions.py), но я все еще не на 100% уверен, что у меня есть он право.

Вот мой сценарий:

У меня есть объект конфигурации. Первоначально, я собираюсь инстанцировать одного объекта конфигурации со множеством значений по умолчанию. Эта конфигурация будет передана к нескольким другим объектам (чтобы гарантировать, чтобы все объекты запустились с той же конфигурации). Однако, после того как взаимодействие с пользователем запускается, каждый объект должен настроить свои конфигурации независимо, не влияя на конфигурации друг друга (который говорит мне, что я должен буду сделать deepcopys своей первоначальной конфигурации для раздавания).

Вот демонстрационный объект:

class ChartConfig(object):

    def __init__(self):

        #Drawing properties (Booleans/strings)
        self.antialiased = None
        self.plot_style = None
        self.plot_title = None
        self.autoscale = None

        #X axis properties (strings/ints)
        self.xaxis_title = None
        self.xaxis_tick_rotation = None
        self.xaxis_tick_align = None

        #Y axis properties (strings/ints)
        self.yaxis_title = None
        self.yaxis_tick_rotation = None
        self.yaxis_tick_align = None

        #A list of non-primitive objects
        self.trace_configs = []

    def __copy__(self):
        pass

    def __deepcopy__(self, memo):
        pass 

Что правильный путь состоит в том, чтобы реализовать copy и deepcopy методы на этом объекте удостовериться copy.copy и copy.deepcopy дайте мне правильное поведение?

82
задан Eino Gourdin 22 November 2019 в 11:08
поделиться

2 ответа

Рекомендации по настройке находятся в самом конце страницы документации :

Классы могут использовать одни и те же интерфейсы для контролировать копирование, которое они используют для контроль травления. Смотрите описание модуля pickle для получения информации о эти методы. Модуль копирования делает не использовать регистрацию copy_reg модуль.

Чтобы класс мог определить свой собственный копировать реализацию, он может определять специальные методы __ copy __ () и __ deepcopy __ () . Первый призван реализовать мелкую копию операция; никаких дополнительных аргументов нет прошло. Последний призван реализовать операцию глубокого копирования; Это передается один аргумент, памятка Словарь. Если __ deepcopy __ () реализация должна сделать глубокий копия компонента, она должна вызывать функция deepcopy () с компонент в качестве первого аргумента и мемо-словарь в качестве второго аргумента.

Поскольку вы, похоже, не заботитесь о настройке травления, определение __ copy __ и __ deepcopy __ определенно кажется правильным путем для вас.

В частности, для вас. , __ copy __ (мелкая копия) в вашем случае довольно просто ...:

def __copy__(self):
  newone = type(self)()
  newone.__dict__.update(self.__dict__)
  return newone

__ deepcopy __ будет аналогичным (принятие аргумента memo arg), но до возврата ему пришлось бы вызвать self.foo = deepcopy (self.foo, memo) для любого атрибута self.foo , который требует глубокого копирования (по сути, атрибуты, которые являются контейнерами - списки, dicts , непримитивные объекты, которые содержат другие данные через свои __ dict __ s).

68
ответ дан 24 November 2019 в 09:11
поделиться

Я могу немного сбиться с толку, но здесь идет;

Из копии docs ;

  • Мелкая копия создает новый составной объект, а затем (насколько это возможно) вставляет в него ссылки на объекты, найденные в оригинале.
  • Глубокая копия конструирует новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале.

Другими словами: copy () скопирует только верхний элемент, а остальные оставит в качестве указателей на исходную структуру. deepcopy () будет рекурсивно копировать все.

То есть, deepcopy () - это то, что вам нужно.

Если вам нужно сделать что-то действительно конкретное, вы можете переопределить __ copy __ () или __ deepcopy __ () , как описано в руководстве. Лично я

6
ответ дан 24 November 2019 в 09:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: