Как я могу "переопределить" глубокую копию в Python? - PullRequest
4 голосов
/ 14 июня 2010

Я бы хотел переопределить __deepcopy__ для данного класса, сопоставленного с SQLAlchemy, чтобы он игнорировал любые атрибуты SQLA, но глубоко копировал все остальное, что является частью класса.

Я не особенно знаком с переопределением любых встроенных объектов Python, в частности, но у меня есть представление о том, что я хочу.

Давайте просто создадим очень простой класс User, сопоставленный с использованием SQLA.

class User(object):
    def __init__(self, user_id=None, name=None):
        self.user_id = user_id
        self.name = name

Я использовал dir(), чтобы увидеть, до и после сопоставления, какие существуют специфичные для SQLAlchemy атрибуты, и я нашел _sa_class_manager и _sa_instance_state.

Questions
При условии, что это единственные, как бы я игнорировал это при определении __deepcopy__?
Кроме того, есть ли какие-либо атрибуты, которые SQLA вставляет в сопоставленный объект?


(Я задал этот вопрос в предыдущем вопросе (как редактирование через несколько дней после того, как я выбрал ответ на главный вопрос), но я думаю, что опоздал на поезд. Извинения за это.)


Edit - Fixed code thanks to zifot's answer

Единственное, что я получил из документации по Python, это то, что вам нужно определить deepcopy с memo в качестве дополнительного аргумента. После небольшого количества копания я попробовал это:

def __deepcopy__(self, memo):
    dpcpy = self.__class__()
    memo[id(self)] = dpcpy
    for attr in dir(self):
        if not attr.startswith('_'):
            value = getattr(self, attr)
            setattr(dpcpy, attr, copy.deepcopy(value, memo))
    return dpcpy

Затем я создал экземпляр User как:

snake = User(913, 'Snake,S.')  

После этого я попробовал операцию deepcopy как:

snake_dc = copy.deepcopy(snake)

... и snake_dc все еще содержат атрибуты SQLA ...

Я открыт для помощи, предложений и т. Д.

Ответы [ 4 ]

1 голос
/ 16 декабря 2016

При (глубоком) копировании вам не следует звонить __init__, а вместо этого звонить __new__.

Пример:

def __copy__(self):
    cls = self.__class__
    newobject = cls.__new__(cls)
    newobject.__dict__.update(self.__dict__)
    return newobject
1 голос
/ 14 июня 2010

мавн прав .Например, попробуйте изменить инициализацию пользователя на:

def __init__(self, user_id = None, name = None):
        self.user_id = user_id
        self.name = name

Что касается копирования сопоставленных экземпляров, я рекомендую прочитать эту ветку

0 голосов
/ 15 июня 2010

Чтобы исключить столбцы sqlalchemy и сопоставленные атрибуты, вы должны сделать что-то вроде:

for attr in dir(self):
    if not self._sa_class_manager.mapper.has_property(key):
        ...
0 голосов
/ 14 июня 2010

Я не специалист по глубокой копии, но из-за ошибки похоже, что вам нужен конструктор без параметров, чтобы вызвать self.__class__() без параметров.

...