1

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

# 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_defof的解决方案Config,但我希望我可以在不知道类定义的情况下恢复配置(例如,导出到 dict 并另存为 JSON)

2.我尝试将class转换为dict(这样我就可以导出为JSON)

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

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

4

2 回答 2

3

问题的标题是“如何将 python 类转换为 dict”,但我怀疑你真的只是在寻找一种简单的方法来表示(超)参数。

到目前为止,最简单的解决方案是不为此使用类。我已经在一些机器学习教程中看到过这种情况,但我认为这是一个非常丑陋的 hack。它打破了关于类与对象的一些语义,而酸洗的困难就是由此产生的结果。你如何使用这样一个简单的类:

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
)

与 pickle 一起工作得很好(尽管您需要在源代码中的某个位置拥有该类),如果您想使用 JSON Params,您还可以轻松地为该类编写loadsave方法。Params

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

于 2018-05-30T22:05:03.713 回答
0

谢天谢地,@evertheylen 的回答对我来说很棒。但是,代码在 时返回错误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
于 2018-05-31T18:44:14.473 回答