How can I "override" deepcopy in Python?
I'd like to override __deepcopy__
for a given SQLAlchemy-mapped class such that it ignores any SQLA attributes but deepcopies everything else that's part of the class.
I'm not particularly familiar with overriding any of Python's built-in objects in particular but I've got some idea as to what I want.
Let's just make a very simple class User
that's mapped using SQLA.
class User(object):
def __init__(self, user_id=None, name=None):
self.user_id = user_id
self.name = name
I've used dir()
to see, before and after mapping, what SQLAlchemy-specific attributes there are and I've found _sa_class_manager
and _sa_instance_state
.
Questions
__deepcopy__
?
Also, are there any attributes the SQLA injects into the mapped object?
(I asked this in a previous question (as an edit a few days after I selected an answer to the main question, though) but I think I 开发者_高级运维missed the train there. Apologies for that.)
Edit - Fixed code thanks to zifot's answer
The only thing I got out of the Python docs is that you need to define deepcopy with memo
as an extra argument. After a teensy bit of digging around I tried this out:
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
Then I created an instance of User
as:
snake = User(913, 'Snake,S.')
After that, I tried a deepcopy
operation as:
snake_dc = copy.deepcopy(snake)
...and snake_dc
still has the SQLA attributes in it...
I'm all open to help, suggestions, etc.
When (deep-)copying you should not be calling __init__
but instead call __new__
.
An example:
def __copy__(self):
cls = self.__class__
newobject = cls.__new__(cls)
newobject.__dict__.update(self.__dict__)
return newobject
mavnn is right. For example try change your init of User to:
def __init__(self, user_id = None, name = None):
self.user_id = user_id
self.name = name
As for copying mapped instances, I recommend reading this thread
I'm not an expert on deepcopy, but from the error it looks like you need a parameterless constructor to call self.__class__()
without parameters.
To exclude sqlalchemy columns and mapped attributes you would do something along the lines of:
for attr in dir(self):
if not self._sa_class_manager.mapper.has_property(key):
...
精彩评论