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
joeHuang
V2EX  ›  Python

pickle、copy_reg 为缺失的属性提供默认值的一个问题

  •  
  •   joeHuang · 2018-08-11 19:40:51 +08:00 · 1744 次点击
    这是一个创建于 2321 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我电脑的 python 是2.7.10,在看picklecopy_reg为缺失的属性提供默认值的时候遇到了一个问题,具体如下:

    1. 先把仅有两个属性的GameState创建对象,并做序列化操作,保存到文件里。
    2. 然后GameState类新增加了属性point,这里用copy_reg来注册相应的行为,再进行反序列化操作

    问题:在进行反序列操作后,新的属性没有被构造。这里如果序列化操作不保存到文件,整个操作又能正常,而不管是从文件里读还是strpickle实际调用的函数是一样的。找不到具体原因。求大神指点。

    # 对应第一步
    class GameState(object):
        def __init__(self):
            self.level = 0
            self.lives = 4
    
    state = GameState()
    state.level += 1
    state.lives -= 1
    print state.__dict__
    '''
    {'lives': 3, 'level': 1}
    '''
    
    import pickle
    state_path = './game_state.pickle'
    with open(state_path, 'wb') as f:
        pickle.dump(state, f)
    
    # 对应第二步
    class GameState(object):
        def __init__(self, level=0, lives=4, point=0):
            self.level = level
            self.lives = lives
            self.point = point
    
    def pickle_obj(obj):
        kwargs = obj.__dict__
        return unpickle_obj, (kwargs,)
    
    def unpickle_obj(kwargs):
        return GameState(**kwargs)
    
    import copy_reg
    copy_reg.pickle(GameState, pickle_obj)
    
    import pickle
    state_path = './game_state.pickle'
    with open(state_path, 'rb') as f:
        state_after = pickle.load(f)
    print state_after.__dict__
    '''
    {'lives': 3, 'level': 1}
    '''
    
    2 条回复    2018-08-13 15:59:01 +08:00
    joeHuang
        1
    joeHuang  
    OP
       2018-08-12 22:20:41 +08:00
    昨天在 Python3.6 下试了下也有一样的问题。
    joeHuang
        2
    joeHuang  
    OP
       2018-08-13 15:59:01 +08:00
    找到原因了。正确的使用方式应该是第一次创建类的时候,就进行注册。
    ~~~python
    class GameState(object):
    def __init__(self):
    self.level = 0
    self.lives = 4

    def pickle_obj(obj):
    kwargs = obj.__dict__
    return unpickle_obj, (kwargs,)

    def unpickle_obj(kwargs):
    return GameState(**kwargs)

    import copy_reg
    copy_reg.pickle(GameState, pickle_obj)

    state = GameState()
    state.level += 2
    state.lives -= 3
    print state.__dict__
    '''
    {'lives': 1, 'level': 2}
    '''

    import pickle
    state_path = './game_state_v2.pickle'

    with open(state_path, 'wb') as f:
    pickle.dump(state, f)

    class GameState(object):
    def __init__(self, level=0, lives=4, point=0):
    self.level = level
    self.lives = lives
    self.point = point

    with open(state_path, 'rb') as f:
    state_after = pickle.load(f)
    print state_after.__dict__
    '''
    {'point': 0, 'lives': 1, 'level': 2}
    '''
    ~~~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5888 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 01:50 · PVG 09:50 · LAX 17:50 · JFK 20:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.