为了简化解析/创建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
当尝试设置属性时,
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)
似乎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
嵌套的EAFP似乎有点难以维护,我的问题是:
- 是否有一种更简单的方法来处理get和set函数的束数据对象?
- 是否有其他类似Dict的对象允许属性和键之间的可变性?
- 束对象的
.update()
函数应该如何工作,浅复制还是深复制?还是让默认的dict.update()
做它该做的?理解dict.copy() -浅还是深?
幸运的是,所有对象都有一个内部的类似字典的对象来管理对象的属性(这是在__dict__
属性中)。要做您所要求的,您只需要使类使用自己作为__dict__
对象:
class Bunch(dict):
def __init__(self, *args, **kwargs):
self.__dict__ = self
super().__init__(*args, **kwargs)
用法:
>>> b = Bunch()
>>> b.foo = 3
>>> b["foo"]
3
>>> b["foo"] = 5
>>> b.foo
5
>>> b["bar"] = 1
>>> b.bar
1