简体   繁体   English

为什么 dict.get(key) 而不是 dict[key]?

[英]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_valueNone ,这样

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?任何地方都有速度改进吗?

As mentioned here ,正如这里提到的,

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 in dict['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 or if statement, this much care for a dictionary term will quickly pile up.虽然我们可以将我们的语句包装在try / exceptif语句中,但对字典术语的这种关注很快就会堆积起来。

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预期默认值):

  • Prefer writing standard, idiomatic code using the tools provided by the language.更喜欢使用该语言提供的工具编写标准的惯用代码。 Python programmers usually (correctly) prefer brackets for the exception safety reasons given above and because it's the default behavior for Python dicts.由于上面给出的异常安全原因,Python 程序员通常(正确地)更喜欢括号,因为它是 Python dicts 的默认行为。
  • Always using .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放弃意图。
  • Testing increases in complexity in proportion to the new "legal" program paths permitted by .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 提供替代方法(分别为atfetch )来选择在错误访问时抛出错误,而 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]?

0. Summary 0. 总结

Comparing to dict[key] , dict.get provides a fallback value when looking up for a key.dict[key]相比, dict.get在查找键时提供了一个备用值。

1. Definition一、定义

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'

2. Problem it solves. 2.它解决的问题。

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引入了一个可选的默认值,避免了上面那些笨拙的代码。

3. Conclusion三、结论

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 .我没有看到的另一个用例是作为sortedmaxmin等函数的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]

Short answer简短的回答

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()方法用于无条件查找,因为提供了默认值,因此永远不会失败。

Base method and helper method基本方法和辅助方法

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM