V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
banxi1988
V2EX  ›  Python

轻轻吐槽下python的deepcopy居然一点不deep

  •  
  •   banxi1988 ·
    banxi1988 · 2013-05-16 22:59:39 +08:00 · 4406 次点击
    这是一个创建于 3997 天前的主题,其中的信息可能已经有所发展或是发生改变。
    在我看来一个对象的copy至少也得改小引用吧。
    但python的不是。
    sqlalchemy
    我是这样做的:
    wendy = session.query(User).filter_by(name='wendy').one()
    In [3]: wendy
    Out[3]: <User('wendy','Wendy Williams','foobar')>
    In [7]: import copy

    In [10]: clone_user = copy.deepcopy(wendy)
    In [11]: clone_user
    Out[11]: <User('wendy','Wendy Williams','foobar')>

    In [12]: clone_user.name='clone_wendy'

    In [13]: clone_user
    Out[13]: <User('clone_wendy','Wendy Williams','foobar')>

    In [14]: wendy
    Out[14]: <User('wendy','Wendy Williams','foobar')>

    In [15]: session.add(clone_user)
    -------------------------------------
    然后出错了。。。

    /Users/yautou/work/python/youjia/ENV/lib/python2.7/site-packages/sqlalchemy/orm/identity.pyc in add(self, state)
    117 "A conflicting state is already "
    118 "present in the identity map for key %r"
    --> 119 % (key, ))
    120 else:
    121 return

    AssertionError: A conflicting state is already present in the identity map for key (<class '__main__.User'>, (1,))
    7 条回复    1970-01-01 08:00:00 +08:00
    Esay
        1
    Esay  
       2013-05-17 09:06:50 +08:00
    怀疑是不是wendy的主键也被复制给了clone_user,你插入的时候,主键重复了,所以会这样。
    yetone
        2
    yetone  
       2013-05-17 10:35:34 +08:00 via Android
    主键重复
    lqs
        3
    lqs  
       2013-05-17 12:13:16 +08:00
    sqlalchemy的session机制就是为了将多个同样的实例只在内存里留一份,然后被deepcopy了它就没法处理了
    yueyoum
        4
    yueyoum  
       2013-05-17 19:43:47 +08:00
    LZ是不是感到python很好学?

    结果什么都不知道吧

    __deepcopy__
    banxi1988
        5
    banxi1988  
    OP
       2013-05-17 22:28:01 +08:00
    @Esay
    @yetone
    你们这么一说我试了下,但还是会抱错:
    In [15]: ed = session.query(User).filter_by(name='ed').one()
    In [22]: import copy
    In [23]: clone_ed = copy.deepcopy(ed)
    In [24]: clone_ed
    Out[24]: <User('ed','Ed Jones','edspassword')>

    In [25]: clone_ed.id
    Out[25]: 4

    In [26]: ed.id
    Out[26]: 4

    In [27]: clone_ed.id = None

    In [28]: clone_ed.name = 'clone ed'

    In [29]: session.add(clone_ed)
    ---------------------------------------------------------------------------
    AssertionError Traceback (most recent call last)
    <ipython-input-29-c3ecb2f64abe> in <module>()
    ----> 1 session.add(clone_ed)

    /Users/yautou/work/python/youjia/ENV/lib/python2.7/site-packages/sqlalchemy/orm/session.pyc in add(self, instance, _warn)
    1396 raise exc.UnmappedInstanceError(instance)
    1397
    -> 1398 self._save_or_update_state(state)
    1399
    1400 def add_all(self, instances):

    /Users/yautou/work/python/youjia/ENV/lib/python2.7/site-packages/sqlalchemy/orm/session.pyc in _save_or_update_state(self, state)
    1408
    1409 def _save_or_update_state(self, state):
    -> 1410 self._save_or_update_impl(state)
    1411
    1412 mapper = _state_mapper(state)

    /Users/yautou/work/python/youjia/ENV/lib/python2.7/site-packages/sqlalchemy/orm/session.pyc in _save_or_update_impl(self, state)
    1664 self._save_impl(state)
    1665 else:
    -> 1666 self._update_impl(state)
    1667
    1668 def _delete_impl(self, state):

    /Users/yautou/work/python/youjia/ENV/lib/python2.7/site-packages/sqlalchemy/orm/session.pyc in _update_impl(self, state, discard_existing)
    1657 self.identity_map.replace(state)
    1658 else:
    -> 1659 self.identity_map.add(state)
    1660 self._attach(state)
    1661

    /Users/yautou/work/python/youjia/ENV/lib/python2.7/site-packages/sqlalchemy/orm/identity.pyc in add(self, state)
    117 "A conflicting state is already "
    118 "present in the identity map for key %r"
    --> 119 % (key, ))
    120 else:
    121 return

    AssertionError: A conflicting state is already present in the identity map for key (<class '__main__.User'>, (4,))

    In [30]: clone_ed
    Out[30]: <User('clone ed','Ed Jones','edspassword')>

    In [31]: clone_ed.id

    In [32]:



    @yueyoum 我google过,但是我觉得还让我去实现个__deepcopy__ 我不如直接自己写一个clone()
    方法。


    @lqs 判断同样实例的是?id我上面测了,不是的。
    yuelang85
        6
    yuelang85  
       2013-05-17 22:58:27 +08:00
    楼主看清报错信息,说得很明白了,主键重复。

    请不要用None做试验。。。。
    lqs
        7
    lqs  
       2013-05-17 23:51:44 +08:00   ❤️ 2
    @banxi1988 在 session.identity_map 保存了所有的对象。

    lone_ed.id = None 这句的意思是『下次保存时把 id 从 4 改成 None 』,而不是『建立一个新的对象』。sqlalchemy会记住『这个对象的 id 以前是 4』。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2707 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 15:51 · PVG 23:51 · LAX 08:51 · JFK 11:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.