在 Python 中,将“dict”与关键字或匿名词典一起使用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1929274/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 23:22:59  来源:igfitidea点击:

In Python, use "dict" with keywords or anonymous dictionaries?

python

提问by Kirk Strauser

Say you want to pass a dictionary of values to a function, or otherwise want to work with a short-lived dictionary that won't be reused. There are two easy ways to do this:

假设您想将值字典传递给函数,或者希望使用不会重用的短期字典。有两种简单的方法可以做到这一点:

Use the dict()function to create a dictionary:

使用dict()函数创建字典:

foo.update(dict(bar=42, baz='qux'))

Use an anonymous dictionary:

使用匿名字典:

foo.update({'bar': 42, 'baz': 'qux'})

Which do you prefer? Are there reasons other than personal style for choosing one over the other?

你喜欢哪个?除了个人风格之外,是否还有其他原因选择其中之一?

回答by Dave Webb

I prefer the anonymous dict option.

我更喜欢匿名 dict 选项。

I don't like the dict()option for the same reason I don't like:

我不喜欢该dict()选项的原因与我不喜欢的原因相同:

 i = int("1")

With the dict()option you're needlessly calling a function which is adding overhead you don't need:

使用该dict()选项,您会不必要地调用一个会增加您不需要的开销的函数:

>>> from timeit import Timer
>>> Timer("mydict = {'a' : 1, 'b' : 2, 'c' : 'three'}").timeit()
0.91826782454194589
>>> Timer("mydict = dict(a=1, b=2, c='three')").timeit()
1.9494664824719337

回答by Peter Hansen

I think in this specific case I'd probably prefer this:

我认为在这种特定情况下,我可能更喜欢这样:

foo.update(bar=42, baz='qux')

In the more general case, I often prefer the literal syntax (what you call an anonymous dictionary, though it's just as anonymous to use {}as it is to use dict()). I think that speaks more clearly to the maintenance programmer (often me), partly because it stands out so nicely with syntax-highlighting text editors. It also ensures that when I have to add a key which is not representable as a Python name, like something with spaces, then I don't have to go and rewrite the whole line.

在更一般的情况下,我通常更喜欢文字语法(您称之为匿名字典,尽管使用匿名和使用{}一样匿名dict())。我认为这对维护程序员(通常是我)来说更清楚,部分原因是它在语法高亮文本编辑器中非常突出。它还确保当我必须添加一个不能表示为 Python 名称的键时,比如带有空格的东西,那么我不必去重写整行。

回答by Beni Cherniavsky-Paskin

My answer will largely talk about the design of APIs to use dicts vs. keyword args. But it's also applicable the individual use of {...}vs. dict(...).

我的回答将主要讨论使用 dicts 与关键字 args 的 API 设计。但它也适用于{...}vs.的个人使用dict(...)

The bottom line: be consistent. If most of your code will refer to 'bar'as a string - keep it a string in {...}; if you normally refer to it the identifier bar- use dict(bar=...).

底线:保持一致。如果您的大部分代码将引用'bar'为字符串 - 将其保留为字符串{...};如果您通常将其称为标识符bar- 使用dict(bar=...)

Constraints

约束

Before talking about style, note that the keyword bar=42syntax works only for strings and only if they are valid identifiers. If you need arbitrary punctuation, spaces, unicode - or even non-string keys - the question is over => only the {'bar': 42}syntax will work.

在讨论样式之前,请注意关键字bar=42语法仅适用于字符串并且仅当它们是有效标识符时才有效。如果您需要任意标点符号、空格、unicode - 甚至非字符串键 - 问题就结束了 => 只有{'bar': 42}语法有效。

This also means that when designing an API, you must allow full dicts, and not only keyword arguments - unless you are sure that only strings, and only valid identifiers are allowed. (Technically, update(**{'spaces & punctuation': 42})works. But it's ugly. And numbers/tuples/unicode won't work.)

这也意味着在设计 API 时,您必须允许使用完整的字典,而不仅仅是关键字参数——除非您确定只允许使用字符串和有效标识符。(从技术上讲,update(**{'spaces & punctuation': 42})可行。但它很丑。数字/元组/unicode 不起作用。)

Note that dict()and dict.update()combine both APIs: you can pass a single dict, you can pass keyword args, and you can even pass both (the later I think is undocumented). So if you want to be nice, allow both:

请注意,dict()dict.update()结合这两个 API:您可以传递单个 dict,您可以传递关键字 args,您甚至可以传递两者(我认为后者是未记录的)。因此,如果您想变得友善,请同时允许:

def update(self, *args, **kwargs):
    """Callable as dict() - with either a mapping or keyword args:

    .update(mapping)
    .update(**kwargs)
    """
    mapping = dict(*args, **kwargs)
    # do something with `mapping`...

This is especially recommended for a method named .update(), to follow the least-surprise rule.

对于名为 的方法.update(),特别推荐这样做,以遵循最小意外规则。

Style

风格

I find it nice to distinguish internalfrom externalstrings. By internal I mean arbitrary identifiers denoting something only inside the program (variable names, object attributes) or possibly between several programs (DB columns, XML attribute names). They are normally only visible to developers. External strings are intended for human consumption.

我发现区分内部字符串和外部字符串很好。我所说的内部是指仅在程序内部(变量名称、对象属性)或可能在多个程序之间(DB 列、XML 属性名称)表示某些内容的任意标识符。它们通常只对开发人员可见。外部字符串供人类使用。

[Some Python coders (me included) observe the convention of using 'single_quotes'for internal strings vs. "Double quotes"for external strings. This is definitely not universal, though.]

[一些 Python 编码人员(包括我在内)遵守'single_quotes'用于内部字符串与"Double quotes"用于外部字符串的约定。不过,这绝对不是普遍的。]

Your question is about the proper uses of barewords(Perl term) - syntax sugars allowing to omit the quotes quotes altogether on internal strings. Some languages (notably LISP) allow them widely; the Pythonic opportunities to employ barewords are attribute access - foo.barand keyword arguments - update(bar=...).

您的问题是关于裸词(Perl 术语)的正确使用- 允许在内部字符串上完全省略引号的语法糖。一些语言(特别是 LISP)允许它们广泛使用;使用裸词的 Pythonic 机会是属性访问 -foo.bar和关键字参数 - update(bar=...)

The stylistic dilemma here is "Are your strings internal enough to look like identifiers?"

这里的文体困境是“你的字符串是否足够内部看起来像标识符?

If the keys are external strings, the answer is definitely NO:

如果键是外部字符串,答案肯定是否定的:

foo.update({"The answer to the big question": 42})

# which you later might access as:
foo["The answer to the big question"]

If the keys refer to Python identifiers (e.g. object attributes), then I'd say YES:

如果键是指 Python 标识符(例如对象属性),那么我会说是:

foo.update(dict(bar=42))
# As others mentioned, in that case the cleaner API (if possible)
# would be to receive them as **kwargs directly:
foo.update(bar=42)

# which you later might access as:
foo.bar

If the keys refer to identifiers outside your Python program, such as XML attr names, or DB column names, using barewords may be good or bad choice - but you it's best to choose one style and be consistent.

如果键引用 Python 程序之外的标识符,例如 XML attr 名称或 DB 列名称,则使用裸词可能是好的或坏的选择 - 但您最好选择一种样式并保持一致

Consistency is good because there is a psychological barrier between identifiers and strings. It exists because strings rarely cross it - only when using introspection to do meta-programming. And syntax highlighting only reinforces it. So if you read the code and see a green 'bar'in one place and a black foo.barin a second place, you won't immediately make a connection.

一致性很好,因为标识符和字符串之间存在心理障碍。它存在是因为字符串很少穿过它 - 仅在使用内省进行元编程时。语法高亮只会加强它。因此,如果您阅读代码并'bar'在一处看到绿色而foo.bar在第二处看到黑色,您将不会立即建立连接。

Another important rule of thumb is: Barewords are good iff they are (mostly) fixed. E.g. if you refer to fixed DB columns mostly in your code, than using barewords to refer to them might be nice; but if half the time the column is a parameter, then it's better to use strings.

另一个重要的经验法则是:如果它们(大部分)是固定的,Barewords 是好的。例如,如果您在代码中主要引用固定的 DB 列,那么使用裸词来引用它们可能会更好;但是如果有一半的时间列是参数,那么最好使用字符串。

This is because parameter/constant is the most important difference people associate with the identifiers/strings barrier. The difference between column(variable) and "person"(constant) is the most readable way to convey this difference. Making them both identifiers would blur the distinction, as well as backfiring syntactically - you'd need to use **{column: value}and getattr(obj, column)etc. a lot.

这是因为参数/常量是人们与标识符/字符串屏障相关联的最重要的区别。column(variable) 和"person"(constant)之间的差异是传达这种差异的最易读的方式。让他们两个标识符将模糊的区别,以及语法事与愿违-你需要使用**{column: value}getattr(obj, column)等了很多。

回答by Mark Peters

The dict() method has the added overhead of a function call.

dict() 方法增加了函数调用的开销。

>>>import timeit,dis
>>> timeit.Timer("{'bar': 42, 'baz': 'qux'}").repeat()
[0.59602910425766709, 0.60173793037941437, 0.59139834811408321]
>>> timeit.Timer("dict(bar=42, baz='qux')").repeat()
[0.98166498814792646, 0.97745355904172015, 0.99231773870701545]

>>> dis.dis(compile("{'bar': 42, 'baz': 'qux'}","","exec"))
  1           0 BUILD_MAP                0
              3 DUP_TOP
              4 LOAD_CONST               0 (42)
              7 ROT_TWO
              8 LOAD_CONST               1 ('bar')
             11 STORE_SUBSCR
             12 DUP_TOP
             13 LOAD_CONST               2 ('qux')
             16 ROT_TWO
             17 LOAD_CONST               3 ('baz')
             20 STORE_SUBSCR
             21 POP_TOP
             22 LOAD_CONST               4 (None)
             25 RETURN_VALUE

>>> dis.dis(compile("dict(bar=42, baz='qux')","","exec"))
  1           0 LOAD_NAME                0 (dict)
              3 LOAD_CONST               0 ('bar')
              6 LOAD_CONST               1 (42)
              9 LOAD_CONST               2 ('baz')
             12 LOAD_CONST               3 ('qux')
             15 CALL_FUNCTION          512
             18 POP_TOP
             19 LOAD_CONST               4 (None)
             22 RETURN_VALUE

回答by Derek Swingley

I prefer your "anonymous dictionary" method and I think this is purely a personal style thing. I just find the latter version more readable but it's also what I'm used to seeing.

我更喜欢你的“匿名字典”方法,我认为这纯粹是个人风格。我只是发现后一个版本更具可读性,但这也是我习惯看到的。

回答by ?aphink

I prefer the anonymous dictionary, too, just out of personal style.

我也更喜欢匿名词典,只是出于个人风格。

回答by gahooa

If I have a lot of arguments, sometimes it is nice to omit the quotes on the keys:

如果我有很多参数,有时省略键上的引号会很好:

DoSomething(dict(
   Name = 'Joe',
   Age = 20,
   Gender = 'Male',
   ))

This is a very subjective question, BTW. :)

这是一个非常主观的问题,顺便说一句。:)

回答by Aaron Lockey

I think the dict()function is really there for when you're creating a dict from something else, maybe something that easily produces the necessary keyword args. The anonymous method is best for 'dict literals' in the same way you'd use "" for strings, not str().

我认为dict()当你从其他东西创建一个 dict 时,这个函数真的存在,也许是很容易产生必要的关键字参数的东西。匿名方法最适合 'dict 文字',就像您对字符串使用 "" 而不是 str() 一样。

回答by jsbueno

Actually, if the receiving function will only receive a dictionary with not pre-dertermined keywords, I normally use the ** passing convention.

实际上,如果接收函数只接收一个没有预先确定关键字的字典,我通常使用 ** 传递约定。

In this example, that would be:

在这个例子中,这将是:

class Foo(object):
   def update(self, **param_dict):
       for key in param_dict:
          ....
foo = Foo()
....
foo.update(bar=42, baz='qux')