编码风格:lightweight/simplest 创建支持属性赋值的实例的方式?

coding style: lightweight/simplest way to create instances supporting attribute assignment?

我经常需要创建一个结果对象实例来 return 来自函数的复杂值,并且想知道什么是好的 Pythonic 方法。

我知道密切相关的 attribute-assignment-to-built-in-object,但它问他为什么需要破解一个 subclass 解决方法才能使用 'object'。我明白为什么了。相反,我问的是标准库中是否存在通过现有 class 或函数避免使用 'object' 和 subclass hack 的现有支持。

实例化支持属性分配的实例的最简单、最 Pythonic 的方法是什么?

我可以直接返回子classing 'object' 答案。这真的没什么大不了的 - 只是想知道我是否错过了标准库或内置支持的更简洁的方法。

我正在尝试做的示例:

try:
    returnval = object()
    returnval.foo = 1
    returnval.bar = 2

    print "\n\nSuccess with %s" % (returnval), vars(returnval), "has __slots__:", hasattr(returnval, "__slots__"), "has __dict__:", hasattr(returnval, "__dict__")

except Exception, e:
    print "\n\nFailure with %s:%s" % (returnval, e), "has __slots__:", hasattr(returnval, "__slots__"), "has __dict__:", hasattr(returnval, "__dict__")

正如预期的那样失败了

Failure with <object object at 0x102c520a0>:'object' object has no attribute 'foo' has __slots__: False has __dict__: False

我并不感到惊讶。 'object' 是裸存根,不允许属性分配,因为它没有 __dict__.

相反,我必须声明一个占位符 class。有更清洁的方法吗?

try:
    class Dummy(object): pass

    returnval = Dummy()
    returnval.foo = 1
    returnval.bar = 2
    print "\n\nSuccess with %s" % (returnval), vars(returnval), "has __slots__:", hasattr(returnval, "__slots__"), "has __dict__:", hasattr(returnval, "__dict__")

except Exception, e:
    print "\n\nFailure with %s:%s" % (returnval, e), "has __slots__:", hasattr(returnval, "__slots__"), "has __dict__:", hasattr(returnval, "__dict__")

这给出:

Success with <__main__.Dummy object at 0x102d5f810> {'foo': 1, 'bar': 2} has __slots__: False has __dict__: True

使用 Dummy/MyClass 方法可以避免这些问题,但它会散发出轻微的代码气味,让我的模块中充满 Dummy classes。

不会work/are不满意的东西:

词典。如果我改用字典,我会避免这种情况,但我会失去简单的 returnval.foo 访问权限。

也许是 AttrDict 实现?但是那些来自第三方包,而不是标准库。

嘲讽。不是我想在这里使用的,因为这不是测试代码,我希望在 returnval.foo 不存在时抛出异常。

Module/class属性赋值。是的,我可以将属性分配给命名空间中的现有对象,例如 class 或模块声明。但这本质上是将属性分配给单例,连续的函数调用会互相破坏。

一种轻量级的方法是使用函数作为容器

>>> foo = lambda: 0
>>> foo.bar = 'bar'
>>> foo.baz = 'baz'

如果你正在制作一堆具有相同属性的不可变对象 collections.namedtuple 可能更合适

>>> foo = namedtuple("foo", "bar, baz")
>>> Foo = foo('bar', 'baz')
>>> foo.bar
'bar'
>>> foo.baz
'baz'

或者使用 namedtuple or stick with a dictionary - if you really want an attribute access - create your own class for it:

>>> Dummy = namedtuple('Dummy', ['foo', 'bar'])
>>> d = Dummy(1, 2)
>>> d
Dummy(foo=1, bar=2)
>>> d.baz
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Dummy' object has no attribute 'baz'