在Python 3.4+中,为什么不使用dict时,为什么我应该在SimpleNamespace上使用namedtuple,它们看起来非常相似


11

在某一点上,您可能会遇到带有很多参数的函数。有时将一些参数组合成超级参数是有意义的。我经常用字典来做,但是现在我正在寻找更好的做事方法。

我想转身...

def do_something(ax, ay, az, bu, bv, c):
    # Do something

...进入...

def do_something(a, b, c):
    # Do something

... ab包含其子变量。

一种方法是执行以下操作:

A = namedtuple('A', 'x, y, z')
a = A(ax, ay, az)
B = namedtuple('B', 'u, v')
b = B(bu, bv)

但是,这似乎更简单:

a = SimpleNamespace(x=ax, y=ay, z=az)
b = SimpleNamespace(u=bu, v=bv)

缺点是什么?ab没有正确键入的事实?它们不是A和B对象吗?

(顺便说一句,不用担心变量名。我通常不将其用作缩写变量名。)


1
本身没有缺点,它们只是不同的东西。对于初学者来说,命名空间是不可变的,而命名空间是可变的。可变比不变好还是变坏?在许多情况下,这取决于您的需要或想要的东西。您的函数可能会与具有所需属性的任何对象一起使用,如何构建它取决于调用方。
停止伤害Monica's

@Goyo谢谢。“缺点”是一种笨拙的说法。我并不是要暗示一个在本质上比另一个要好。只是想要优点和缺点。再次感谢。
安德烈·克里斯托弗·安徒生

1
第四行看起来不应该是“ b = B(bu,bv)”吗?
艾伦·西雅克

@AlenSiljak是的。我现在修复它。
安德烈·克里斯托弗·安徒生

Answers:


21

SimpleNamespace基本上只是字典顶部的一个不错的外观。它允许您使用属性而不是索引键。很好,因为它超级灵活且易于操作。

这种灵活性的缺点是它不提供任何结构。没有什么可以阻止某人打来的电话SimpleNamespace(x=ax, y=ay)(以及del a.z稍后再打)。如果将此实例传递给函数,则在尝试访问该字段时会发生异常。

相反,namedtuple让您创建结构化类型。该类型将有一个名称,并且它将知道它应该具有哪些字段。没有这些字段中的每个字段,您将无法创建实例,以后也无法删除它们。另外,该实例是不可变的,因此您将知道in中的值a.x将始终相同。

由您决定是否需要SimpleNamespace给您的灵活性,或者您是否更喜欢由提供的结构和保证namedtuple


2

我真的很喜欢有关结构化与非结构化的答案,因此我在下面提供一个具体示例。

SimpleNamespace将接受以开头的键_。如果您正在寻找一种快速简便的方法来转换JSON(例如,您不将其控制为具有字段名称的对象),则这非常方便:

d = {"_id": 2342122, "text": "hi there!"} # Elasticsearch gives this id!
e = SimpleNamespace(**d) # works
Name = namedtuple("Name", sorted(d)) # ValueError so we can't do Name(**d)

请注意,您可以看到上面的内容namedtuple为我们提供了一个SimpleNamespace永远不会提供的额外对象。每个SimpleNamespace实际上都是一个“独特的雪花”,而namedtuple存在却从未被任何具体的值实例化。在需要抽象化具体值的地方,您可能应该选择它。


1

的总结 SimpleNamespace

它允许在构造对象时初始化属性:

sn = SimpleNamespace(a=1, b=2)

它提供了一个可读的

repr(): eval(repr(sn)) == sn

它会覆盖默认比较。而不是按进行比较id(),它而是比较属性值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.