在 Bunch 类型对象中设置和获取属性

alv*_*vas 5 python dictionary data-structures bunch

为了简单解析/创建 JSON,机器学习应用程序通常使用Bunch对象,例如https://github.com/dsc/bunch/blob/master/bunch/__init__.py

获取时,有一个嵌套的 EAFP 习语,它检查dict.get()函数,然后尝试使用字典方括号语法访问它,即

class Bunch(dict):
    def __getattr___(self, k):
        try:
            return object.__getattribute__(self, k)
        except AttributeError:
            try: 
                 return self[k]
            except KeyError:
                 raise AttributeError
Run Code Online (Sandbox Code Playgroud)

当试图设置一个属性时,

    def __setattr__(self, k, v):
        try:
            # Throws exception if not in prototype chain
            object.__getattribute__(self, k)
        except AttributeError:
            try:
                self[k] = v
            except:
                raise AttributeError(k)
        else:
            object.__setattr__(self, k, v)
Run Code Online (Sandbox Code Playgroud)

似乎sklearn实现遵循相同的思路,但检查较少https://github.com/scikit-learn/scikit-learn/blob/2beed5584/sklearn/utils/__init__.py#L61

class Bunch(dict):
    def __init__(self, **kwargs):
        super().__init__(kwargs)

    def __setattr__(self, key, value):
        self[key] = value

    def __dir__(self):
        return self.keys()

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(key)

    def __setstate__(self, state):
        # Bunch pickles generated with scikit-learn 0.16.* have an non
        # empty __dict__. This causes a surprising behaviour when
        # loading these pickles scikit-learn 0.17: reading bunch.key
        # uses __dict__ but assigning to bunch.key use __setattr__ and
        # only changes bunch['key']. More details can be found at:
        # https://github.com/scikit-learn/scikit-learn/issues/6196.
        # Overriding __setstate__ to be a noop has the effect of
        # ignoring the pickled __dict__
        pass
Run Code Online (Sandbox Code Playgroud)

嵌套的 EAFP 似乎有点难以维护,我的问题是:

  • 有没有更简单的方法来处理 Bunch 数据对象的 get 和 set 函数?
  • 是否有其他类似 Dict 的对象允许属性和键之间的可变性?
  • Bunch 对象的.update()函数应该如何工作,浅拷贝还是深拷贝?或者只是让默认dict.update()做它所做的? 理解 dict.copy() - 浅还是深?

Ela*_*n-R 3

幸运的是,所有对象都有一个内部类似字典的对象,用于管理对象的属性(这是在属性中__dict__)。要执行您所要求的操作,您只需使该类使用自身作为对象即可__dict__

class Bunch(dict):
    def __init__(self, *args, **kwargs):
        self.__dict__ = self
        super().__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

用法:

>>> b = Bunch()
>>> b.foo = 3
>>> b["foo"]
3
>>> b["foo"] = 5
>>> b.foo
5
>>> b["bar"] = 1
>>> b.bar
1
Run Code Online (Sandbox Code Playgroud)