[英]Why dict.get(key) instead of dict[key]?
Today, I came across the dict
method get
which, given a key in the dictionary, returns the associated value.今天,我遇到了dict
方法get
,它给定字典中的键,返回关联的值。
For what purpose is this function useful?这个功能有什么用? If I wanted to find a value associated with a key in a dictionary, I can just do dict[key]
, and it returns the same thing:如果我想在字典中查找与键关联的值,我可以执行dict[key]
,它返回相同的内容:
dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")
It allows you to provide a default value if the key is missing:如果缺少键,它允许您提供默认值:
dictionary.get("bogus", default_value)
returns default_value
(whatever you choose it to be), whereas返回default_value
(无论您选择什么),而
dictionary["bogus"]
would raise a KeyError
.会引发KeyError
。
If omitted, default_value
is None
, such that如果省略,则default_value
为None
,这样
dictionary.get("bogus") # <-- No default specified -- defaults to None
returns None
just like返回None
就像
dictionary.get("bogus", None)
would.将。
What is the
dict.get()
method?什么是dict.get()
方法?
As already mentioned the get
method contains an additional parameter which indicates the missing value.如前所述, get
方法包含一个指示缺失值的附加参数。 From the documentation从文档
get(key[, default])
Return the value for key if key is in the dictionary, else default.如果键在字典中,则返回键的值,否则返回默认值。 If default is not given, it defaults to None, so that this method never raises a
KeyError
.如果未给出默认值,则默认为无,因此此方法永远不会引发KeyError
。
An example can be一个例子可以是
>>> d = {1:2,2:3}
>>> d[1]
2
>>> d.get(1)
2
>>> d.get(3)
>>> repr(d.get(3))
'None'
>>> d.get(3,1)
1
Are there speed improvements anywhere?任何地方都有速度改进吗?
It seems that all three approaches now exhibit similar performance (within about 10% of each other), more or less independent of the properties of the list of words.似乎所有三种方法现在都表现出相似的性能(彼此相差约 10%),或多或少独立于单词列表的属性。
Earlier get
was considerably slower, However now the speed is almost comparable along with the additional advantage of returning the default value.早期的get
速度要慢得多,但是现在速度几乎可以与返回默认值的额外优势相媲美。 But to clear all our queries, we can test on a fairly large list (Note that the test includes looking up all the valid keys only)但是为了清除我们所有的查询,我们可以在一个相当大的列表上进行测试(注意,测试只包括查找所有有效的键)
def getway(d):
for i in range(100):
s = d.get(i)
def lookup(d):
for i in range(100):
s = d[i]
Now timing these two functions using timeit
现在使用timeit
对这两个函数进行计时
>>> import timeit
>>> print(timeit.timeit("getway({i:i for i in range(100)})","from __main__ import getway"))
20.2124660015
>>> print(timeit.timeit("lookup({i:i for i in range(100)})","from __main__ import lookup"))
16.16223979
As we can see the lookup is faster than the get as there is no function lookup.正如我们所见,查找比获取更快,因为没有函数查找。 This can be seen through dis
这可以通过dis
看到
>>> def lookup(d,val):
... return d[val]
...
>>> def getway(d,val):
... return d.get(val)
...
>>> dis.dis(getway)
2 0 LOAD_FAST 0 (d)
3 LOAD_ATTR 0 (get)
6 LOAD_FAST 1 (val)
9 CALL_FUNCTION 1
12 RETURN_VALUE
>>> dis.dis(lookup)
2 0 LOAD_FAST 0 (d)
3 LOAD_FAST 1 (val)
6 BINARY_SUBSCR
7 RETURN_VALUE
Where will it be useful?它将在哪里有用?
It will be useful whenever you want to provide a default value whenever you are looking up a dictionary.每当您要在查找字典时提供默认值时,它都会很有用。 This reduces这减少了
if key in dic:
val = dic[key]
else:
val = def_val
To a single line, val = dic.get(key,def_val)
对于单行, val = dic.get(key,def_val)
Where will it be NOT useful?它在哪里没有用处?
Whenever you want to return a KeyError
stating that the particular key is not available.每当您想返回KeyError
说明特定键不可用时。 Returning a default value also carries the risk that a particular default value may be a key too!返回默认值也会带来特定默认值也可能是键的风险!
Is it possible to have
get
like feature indict['key']
?是否有可能在dict['key']
中get
类似的功能?
Yes!是的! We need to implement the __missing__
in a dict subclass.我们需要在 dict 子类中实现__missing__
。
A sample program can be一个示例程序可以是
class MyDict(dict):
def __missing__(self, key):
return None
A small demonstration can be一个小示范可以
>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'
get
takes a second optional value. get
采用第二个可选值。 If the specified key does not exist in your dictionary, then this value will be returned.如果您的字典中不存在指定的键,则将返回此值。
dictionary = {"Name": "Harry", "Age": 17}
dictionary.get('Year', 'No available data')
>> 'No available data'
If you do not give the second parameter, None
will be returned.如果不给第二个参数,则返回None
。
If you use indexing as in dictionary['Year']
, nonexistent keys will raise KeyError
.如果您在dictionary['Year']
中使用索引,则不存在的键将引发KeyError
。
I will give a practical example in scraping web data using python, a lot of the times you will get keys with no values, in those cases you will get errors if you use dictionary['key'], whereas dictionary.get('key', 'return_otherwise') has no problems.<\/i>我将给出一个使用 python 抓取 web 数据的实际示例,很多时候你会得到没有值的键,在这些情况下,如果你使用 dictionary['key'],你会得到错误,而 dictionary.get('key ', 'return_otherwise') 没有问题。<\/b><\/p>
Similarly, I would use ''.join(list) as opposed to list[0] if you try to capture a single value from a list.<\/i>同样,如果您尝试从列表中捕获单个值,我将使用 ''.join(list) 而不是 list[0] 。<\/b><\/p>
hope it helps.<\/i>希望能帮助到你。<\/b><\/p>
[Edit] Here is a practical example:<\/i> [编辑] 这是一个实际的例子:<\/b><\/p>
Say, you are calling an API, which returns a JOSN file you need to parse.<\/i>假设您正在调用一个 API,该 API 返回一个您需要解析的 JOSN 文件。<\/b> The first JSON looks like following:<\/i>第一个 JSON 如下所示:<\/b><\/p>
{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","submitdate_ts":1318794805,"users_id":"2674360","project_id":"1250499"}}
A gotcha to be aware of when using .get()
:使用.get()
时要注意的问题:
If the dictionary contains the key used in the call to .get()
and its value is None
, the .get()
method will return None
even if a default value is supplied.如果字典包含调用.get()
时使用的键并且其值为None
,则.get()
方法将返回None
即使提供了默认值。
For example, the following returns None
, not 'alt_value'
as may be expected:例如,以下返回None
,而不是预期'alt_value'
:
d = {'key': None}
assert None is d.get('key', 'alt_value')
.get()
's second value is only returned if the key supplied is NOT in the dictionary, not if the return value of that call is None
. .get()
的第二个值仅在提供的键不在字典中时返回,而不是在该调用的返回值为None
时返回。
目的是如果没有找到key可以给一个默认值,非常有用
dictionary.get("Name",'harry')
For what purpose is this function useful?这个功能有什么用?
One particular usage is counting with a dictionary.一种特殊的用法是用字典计数。 Let's assume you want to count the number of occurrences of each element in a given list.假设您要计算给定列表中每个元素的出现次数。 The common way to do so is to make a dictionary where keys are elements and values are the number of occurrences.这样做的常用方法是制作一个字典,其中键是元素,值是出现次数。
fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
if fruit not in d:
d[fruit] = 0
d[fruit] += 1
Using the .get()
method, you can make this code more compact and clear:使用.get()
方法,您可以使这段代码更加紧凑和清晰:
for fruit in fruits:
d[fruit] = d.get(fruit, 0) + 1
Other answers have clearly explained the difference between dict bracket keying and .get
and mentioned a fairly innocuous pitfall when None
or the default value is also a valid key.其他答案已经清楚地解释了 dict 括号键控和.get
之间的区别,并提到了一个相当无害的陷阱,当None
或默认值也是有效键时。
Given this information, it may be tempting conclude that .get
is somehow safer and better than bracket indexing and should always be used instead of bracket lookups, as argued in Stop Using Square Bracket Notation to Get a Dictionary's Value in Python , even in the common case when they expect the lookup to succeed (ie never raise a KeyError
).鉴于此信息,可能很容易得出结论,即.get
在某种程度上比括号索引更安全和更好,并且应该始终使用而不是括号查找,如Stop Using Square Bracket Notation to Get a Dictionary's Value in Python中所述,即使在常见的情况下也是如此他们期望查找成功的情况(即永远不会引发KeyError
)。
The author of the blog post argues that .get
"safeguards your code":博客文章的作者认为.get
“保护您的代码”:
Notice how trying to reference a term that doesn't exist causes a
KeyError
.请注意尝试引用不存在的术语如何导致KeyError
。 This can cause major headaches, especially when dealing with unpredictable business data.这可能会让人头疼,尤其是在处理不可预测的业务数据时。While we could wrap our statement in a
try
/except
orif
statement, this much care for a dictionary term will quickly pile up.虽然我们可以将我们的语句包装在try
/except
或if
语句中,但对字典术语的这种关注很快就会堆积起来。
It's true that in the uncommon case for null ( None
)-coalescing or otherwise filling in a missing value to handle unpredictable dynamic data, a judiciously-deployed .get
is a useful and Pythonic shorthand tool for ungainly if key in dct:
and try
/ except
blocks that only exist to set default values when the key might be missing as part of the behavioral specification for the program.确实,在不常见的情况下null ( None
)-合并或以其他方式填充缺失值以处理不可预测的动态数据,明智部署的.get
是一个有用且 Pythonic 的速记工具,用于笨拙if key in dct:
并try
/ except
作为程序行为规范的一部分可能缺少键时仅用于设置默认值的块。
However, replacing all bracket dict lookups, including those that you assert must succeed, with .get
is a different matter.但是,用.get
替换所有括号 dict 查找,包括您断言必须成功的那些查找是另一回事。 This practice effectively downgrades a class of runtime errors that help reveal bugs into silent illegal state scenarios that tend to be harder to identify and debug.这种做法有效地将一类运行时错误降级,这些错误有助于将错误揭示为更难以识别和调试的静默非法状态场景。
A common mistake among programmers is to think exceptions cause headaches and attempt to suppress them, using techniques like wrapping code in try
... except: pass
blocks .程序员之间的一个常见错误是认为异常会引起头痛并试图抑制它们,使用诸如将代码包装在try
... except: pass
blocks中的技术。 They later realize the real headache is never seeing the breach of application logic at the point of failure and deploying a broken application.他们后来意识到,真正令人头疼的事情是永远不会在故障点看到应用程序逻辑被破坏并部署损坏的应用程序。 Better programming practice is to embrace assertions for all program invariants such as keys that must be in a dictionary.更好的编程实践是包含所有程序不变量的断言,例如必须在字典中的键。
The hierarchy of error safety is, broadly:错误安全的层次结构大致是:
Error category错误类别 | Relative ease of debugging调试相对容易 |
---|---|
Compile-time error编译时错误 | Easy;简单的; go to the line and fix the problem去生产线解决问题 |
Runtime exception运行时异常 | Medium;中等的; control needs to flow to the error and it may be due to unanticipated edge cases or hard-to-reproduce state like a race condition between threads, but at least we get a clear error message and stack trace when it does happen.控制需要流向错误,这可能是由于意外的边缘情况或难以重现的状态(如线程之间的竞争条件),但至少当它发生时我们会得到明确的错误消息和堆栈跟踪。 |
Silent logical error沉默的逻辑错误 | Difficult;难的; we may not even know it exists, and when we do, tracking down state that caused it can be very challenging due to lack of locality and potential for multiple assertion breaches.我们甚至可能不知道它的存在,当我们这样做时,由于缺乏局部性和潜在的多个断言违规,追踪导致它的状态可能非常具有挑战性。 |
When programming language designers talk about program safety, a major goal is to surface, not suppress, genuine errors by promoting runtime errors to compile-time errors and promote silent logical errors to either runtime exceptions or (ideally) compile-time errors.当编程语言设计者谈论程序安全时,一个主要目标是通过将运行时错误提升为编译时错误并将静默逻辑错误提升为运行时异常或(理想情况下)编译时错误来显示而不是抑制真正的错误。
Python, by design as an interpreted language, relies heavily on runtime exceptions instead of compiler errors. Python 在设计上是一种解释性语言,它严重依赖运行时异常而不是编译器错误。 Missing methods or properties, illegal type operations like 1 + "a"
and out of bounds or missing indices or keys raise by default.默认情况下,缺少方法或属性、非法类型操作(如1 + "a"
和超出范围或缺少索引或键)。
Some languages like JS, Java, Rust and Go use the fallback behavior for their maps by default (and in many cases, don't provide a throw/raise alternative), but Python throws by default, along with other languages like C#.某些语言,如 JS、Java、Rust 和 Go,默认情况下使用其映射的回退行为(在许多情况下,不提供 throw/raise 替代方案),但 Python 和其他语言(如 C#)默认情况下会抛出。 Perl/PHP issue an uninitialized value warning. Perl/PHP 发出未初始化值警告。
Indiscriminate application of .get
to all dict accesses, even those that aren't expected to fail and have no fallback for dealing with None
(or whatever default is used) running amok through the code, pretty much tosses away Python's runtime exception safety net for this class of errors, silencing or adding indirection to potential bugs. .get
不加选择地应用于所有 dict 访问,即使是那些预计不会失败并且没有后备处理None
(或使用任何默认值)在代码中乱跑的人,几乎抛弃了 Python 的运行时异常安全网这类错误,沉默或增加潜在错误的间接性。
Other supporting reasons to prefer bracket lookups (with the occasional, well-placed .get
where a default is expected):更喜欢括号查找的其他支持原因(偶尔,放置良好的.get
预期默认值):
.get
forfeits intent by making cases when you expect to provide a default None
value indistinguishable from a lookup you assert must succeed.当您希望提供与您断言必须成功的查找无法区分的默认None
值时,始终使用.get
放弃意图。.get
.测试的复杂性与.get
允许的新“合法”程序路径成正比。 Effectively, each lookup is now a branch that can succeed or fail -- both cases must be tested to establish coverage, even if the default path is effectively unreachable by specification (ironically leading to additional if val is not None:
or try
for all future uses of the retrieved value; unnecessary and confusing for something that should never be None
in the first place).实际上,每个查找现在都是一个可以成功或失败的分支——这两种情况都必须经过测试以建立覆盖范围,即使默认路径实际上无法通过规范到达(具有讽刺意味的是, if val is not None:
或try
所有未来检索到的值的用途;对于本来不应该是None
的东西来说是不必要的和令人困惑的)。.get
is a bit slower . .get
有点慢。.get
is harder to type and uglier to read (compare Java's tacked-on-feel ArrayList
syntax to native-feel C# Lists
or C++ vector code). .get
更难输入,也更难读(将 Java 附加的ArrayList
语法与原生 C# Lists
或 C++ 矢量代码进行比较)。 Minor.次要的。 Some languages like C++ and Ruby offer alternate methods ( at
and fetch
, respectively) to opt-in to throwing an error on a bad access, while C# offers opt-in fallback value TryGetValue
similar to Python's get
.一些语言,如 C++ 和 Ruby 提供替代方法(分别为at
和fetch
)来选择在错误访问时抛出错误,而 C# 提供类似于 Python 的get
的选择后备值TryGetValue
。
Since JS, Java, Ruby, Go and Rust bake the fallback approach of .get
into all hash lookups by default, it can't be that bad, one might think.由于 JS、Java、Ruby、Go 和 Rust 默认将.get
的后备方法烘焙到所有哈希查找中,所以它不会那么糟糕,人们可能会想。 It's true that this isn't the largest issue facing language designers and there are plenty of use cases for the no-throw access version, so it's unsurprising that there's no consensus across languages.诚然,这不是语言设计者面临的最大问题,并且无抛出访问版本有很多用例,因此跨语言没有达成共识也就不足为奇了。
But as I've argued, Python (along with C#) has done better than these languages by making the assert option the default.但正如我所论证的,Python(连同 C#)通过将 assert 选项设为默认值,比这些语言做得更好。 It's a loss of safety and expressivity to opt-out of using it to report contract violations at the point of failure by indiscriminately using .get
across the board.通过不加选择地全面使用.get
来选择不使用它在故障点报告合同违规行为是一种安全性和表达能力的损失。
Why dict.get(key) instead of dict[key]?为什么 dict.get(key) 而不是 dict[key]?
Comparing to dict[key]
, dict.get
provides a fallback value when looking up for a key.与dict[key]
相比, dict.get
在查找键时提供了一个备用值。
get(key[, default]) 4. Built-in Types — Python 3.6.4rc1 documentation get(key[, default]) 4. 内置类型 — Python 3.6.4rc1 文档
Return the value for key if key is in the dictionary, else default.如果键在字典中,则返回键的值,否则返回默认值。 If default is not given, it defaults to None, so that this method never raises a KeyError.如果未给出默认值,则默认为无,因此此方法永远不会引发 KeyError。
d = {"Name": "Harry", "Age": 17}
In [4]: d['gender']
KeyError: 'gender'
In [5]: d.get('gender', 'Not specified, please add it')
Out[5]: 'Not specified, please add it'
If without default value
, you have to write cumbersome codes to handle such an exception.如果没有default value
,则必须编写繁琐的代码来处理此类异常。
def get_harry_info(key):
try:
return "{}".format(d[key])
except KeyError:
return 'Not specified, please add it'
In [9]: get_harry_info('Name')
Out[9]: 'Harry'
In [10]: get_harry_info('Gender')
Out[10]: 'Not specified, please add it'
As a convenient solution, dict.get
introduces an optional default value avoiding above unwiedly codes.作为一种方便的解决方案, dict.get
引入了一个可选的默认值,避免了上面那些笨拙的代码。
dict.get
has an additional default value option to deal with exception if key is absent from the dictionary如果字典中没有键, dict.get
有一个额外的默认值选项来处理异常
One difference, that can be an advantage, is that if we are looking for a key that doesn't exist we will get None, not like when we use the brackets notation, in which case we will get an error thrown:一个可能是优势的区别是,如果我们正在寻找一个不存在的键,我们将得到 None,不像我们使用方括号表示法时那样,在这种情况下我们会抛出一个错误:
print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'
Last thing that is cool about the get method, is that it receives an additional optional argument for a default value, that is if we tried to get the score value of a student, but the student doesn't have a score key we can get a 0 instead. get 方法的最后一件很酷的事情是,它接收一个额外的默认值的可选参数,也就是说,如果我们试图获取学生的分数值,但学生没有我们可以获得的分数键一个 0 代替。
So instead of doing this (or something similar):因此,不要这样做(或类似的事情):
score = None
try:
score = dictionary["score"]
except KeyError:
score = 0
We can do this:我们做得到:
score = dictionary.get("score", 0)
# score = 0
One other use-case that I do not see mentioned is as the key
argument for functions like sorted
, max
and min
.我没有看到的另一个用例是作为sorted
、 max
和min
等函数的key
参数。 The get
method allows for keys to be returned based on their values. get
方法允许根据键的值返回键。
>>> ages = {"Harry": 17, "Lucy": 16, "Charlie": 18}
>>> print(sorted(ages, key=ages.get))
['Lucy', 'Harry', 'Charlie']
>>> print(max(ages, key=ages.get))
Charlie
>>> print(min(ages, key=ages.get))
Lucy
Thanks to this answer to a different question for providing this use-case!感谢提供此用例的另一个问题的答案!
It allow you to provide a default value, instead of get an error when the value is not found.它允许您提供默认值,而不是在找不到该值时出错。 persuedocode like this :像这样说服代码:
class dictionary():
def get(self,key,default):
if self[key] is not found :
return default
else:
return self[key]
The square brackets are used for conditional lookups which can fail with a KeyError
when the key is missing.方括号用于条件查找,当缺少键时,可能会因KeyError
而失败。
The get()
method is used from unconditional lookups that never fail because a default value has been supplied. get()
方法用于无条件查找,因为提供了默认值,因此永远不会失败。
The square brackets call the __getitem__
method which is fundamental for mappings like dicts.方括号调用__getitem__
方法,该方法是 dicts 等映射的基础。
The get()
method is a helper layered on top of that functionality. get()
方法是分层在该功能之上的帮助程序。 It is a short-cut for the common coding pattern:它是通用编码模式的捷径:
try:
v = d[k]
except KeyError:
v = default_value
Based on usage should use this get
method.根据用法应该使用这个get
方法。
Example1示例 1
In [14]: user_dict = {'type': False}
In [15]: user_dict.get('type', '')
Out[15]: False
In [16]: user_dict.get('type') or ''
Out[16]: ''
Example2示例 2
In [17]: user_dict = {'type': "lead"}
In [18]: user_dict.get('type') or ''
Out[18]: 'lead'
In [19]: user_dict.get('type', '')
Out[19]: 'lead'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.