代码之家  ›  专栏  ›  技术社区  ›  YW P Kwon

当使用python类作为程序配置结构(包括继承的类属性)时,保存/恢复的好方法是什么?

  •  1
  • YW P Kwon  · 技术社区  · 6 年前

    假设我有一个(简化的)类,如下所示。我使用它进行程序配置(超参数)。

    # config.py
    class Config(object):      # default configuration
        GPU_COUNT = 1
        IMAGES_PER_GPU = 2
        MAP = {1:2, 2:3}
    
        def display(self):
            pass
    
    # experiment1.py
    from config import Config as Default
    class Config(Default):     # some over-written configuration
        GPU_COUNT = 2
        NAME='2'            
    
    # run.py
    from experiment1 import Config
    cfg = Config()
    ...
    cfg.NAME = 'ABC'            # possible runtime over-writing
    
    # Now I would like to save `cfg` at this moment
    

    我想保存此配置并稍后还原。恢复时必须不考虑成员函数。

    1。当我尝试泡菜时:

    import pickle
    with open('cfg.pk', 'rb') as f: cfg = pickle.load(f)
    
    ##--> AttributeError: Can't get attribute 'Config' on <module '__main__'>
    

    我看到一个解决方案 class_def 属于 Config ,但我希望可以在不知道类定义的情况下恢复配置(例如,导出到dict并另存为json)

    2。我试着把课堂改成听写 (以便我可以导出为json)

    cfg.__dict__     # {'NAME': 'ABC'}
    vars(cfg)        # {'NAME': 'ABC'} 
    

    在这两种情况下,都很难访问属性。有可能吗?

    2 回复  |  直到 6 年前
        1
  •  3
  •   Evert Heylen    6 年前

    问题的标题是“如何将python类转换为dict”,但我怀疑您实际上只是在寻找表示(hyper)参数的简单方法。

    到目前为止,最简单的解决方案是不为此使用类。我在一些机器学习教程上看到过这种情况,但我认为这是一个相当丑陋的黑客。它破坏了类和对象的一些语义,而pickle的困难正是这一点造成的。不如用这样一个简单的类:

    class Params(dict):
        __getattr__ = dict.__getitem__
        __setattr__ = dict.__setitem__
        __delattr__ = dict.__delitem__
    
        def __getstate__(self):
            return self
    
        def __setstate__(self, state):
            self.update(state)
    
        def copy(self, **extra_params):
            return Params(**self, **extra_params)
    

    它可以做类方法所能做的一切。预定义配置只是在编辑之前应复制的对象,如下所示:

    config = Params(
        GPU_COUNT = 2,
        NAME='2',
    )
    other_config = config.copy()
    other_config.GPU_COUNT = 4
    

    或者一步到位:

    other_config = config.copy(
        GPU_COUNT = 4
    )
    

    与泡菜搭配很好(尽管你 需要有 Params 在源代码中的某个地方初始化),并且您还可以轻松地编写 load save 方法 帕拉姆 如果要使用json,请初始化。

    简而言之,不要将类用于真正只是对象的对象。

        2
  •  0
  •   YW P Kwon    6 年前

    谢天谢地,每个人的回答对我都很好。但是,当 p.__class__ = Params ,所以我稍微改变如下。我想也是这样。

    class Params(dict):
        __getattr__ = dict.__getitem__
        __setattr__ = dict.__setitem__
        __delattr__ = dict.__delitem__
    
        def __getstate__(self):
            return self
    
        def __setstate__(self, state):
            self.update(state)
    
        def copy(self, **extra_params):
            lhs = Params()
            lhs.update(self)
            lhs.update(extra_params)
            return lhs
    

    你能做到的

    config = Params(
        GPU_COUNT = 2,
        NAME='2',
    )
    other_config = config.copy()
    other_config.GPU_COUNT = 4