今天,我遇到了dict方法get,它在字典中给定一个键,返回相关的值。
这个函数的用途是什么?如果我想在字典中找到一个与键相关的值,我可以只做dict[key],它返回相同的东西:
dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")
今天,我遇到了dict方法get,它在字典中给定一个键,返回相关的值。
这个函数的用途是什么?如果我想在字典中找到一个与键相关的值,我可以只做dict[key],它返回相同的东西:
dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")
它允许你在缺少键时提供一个默认值:
dictionary.get("bogus", default_value)
返回default_value(不管你选择它是什么),而
dictionary["bogus"]
会引发一个KeyError。
如果省略,default_value为None,这样
dictionary.get("bogus") # <-- No default specified -- defaults to None
返回None
dictionary.get("bogus", None)
会。
Get接受第二个可选值。如果指定的键在您的字典中不存在,则将返回此值。
dictionary = {"Name": "Harry", "Age": 17}
dictionary.get('Year', 'No available data')
>> 'No available data'
如果不提供第二个参数,则返回None。
如果使用dictionary['Year']中的索引,则不存在键将引发KeyError。
我将给出一个使用python抓取web数据的实际示例,很多时候你会得到没有值的键,在这种情况下,如果你使用dictionary['key'],你会得到错误。Get ('key', ' return_else ')没有问题。
类似地,如果您试图从列表中捕获单个值,我将使用“.join(list)”而不是列表[0]。
希望能有所帮助。
下面是一个实际的例子:
假设,您正在调用一个API,该API返回一个需要解析的JOSN文件。第一个JSON如下所示:
{"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"}}
第二个JOSN是这样的:
{"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","users_id":"2674360","project_id":"1250499"}}
请注意,第二个JSON缺少“submitdate_ts”键,这在任何数据结构中都是非常正常的。
因此,当你试图在循环中访问该键的值时,你可以用下面的方法调用它:
for item in API_call:
submitdate_ts = item["bids"]["submitdate_ts"]
您可以这样做,但它会为第二个JSON行提供一个回溯错误,因为键根本不存在。
正确的编码方式如下:
for item in API_call:
submitdate_ts = item.get("bids", {'x': None}).get("submitdate_ts")
{'x': None}的存在是为了避免第二级出错。当然,如果您正在进行抓取,您可以在代码中构建更多的容错性。比如首先指定一个if条件
什么是dict.get()方法?
如前所述,get方法包含一个附加参数,用于指示缺少的值。来自文档
get(键(默认)) 如果key在字典中,则返回key的值,否则为default。如果没有给出default,则默认为None,因此该方法永远不会引发KeyError。
一个例子是
>>> 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
哪里有提高速度的地方吗?
正如这里提到的,
现在看来,这三种方法表现出相似的性能(彼此相差约10%),或多或少与单词列表的属性无关。
早期的get相当慢,但是现在的速度几乎是相当的,以及返回默认值的额外优势。但是为了清除所有的查询,我们可以在一个相当大的列表上进行测试(注意,测试只包括查找所有有效的键)
def getway(d):
for i in range(100):
s = d.get(i)
def lookup(d):
for i in range(100):
s = d[i]
现在使用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
正如我们所看到的,查找比get快,因为没有函数查找。这可以通过这个看出
>>> 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
它在哪里有用?
当您在查找字典时希望提供一个默认值时,它将非常有用。这减少了
if key in dic:
val = dic[key]
else:
val = def_val
val = dic.get(key,def_val)
在哪里它是无用的?
当您希望返回一个KeyError,说明特定的键不可用时。返回默认值也有风险,即特定的默认值也可能是键!
是否可能在dict['key']中有get like特征?
是的!我们需要在dict子类中实现__missing__。
示例程序可以是
class MyDict(dict):
def __missing__(self, key):
return None
一个小小的示范就可以了
>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'
这个函数的用途是什么?
一个特别的用法是用字典计数。让我们假设您想要计算给定列表中每个元素的出现次数。常见的方法是创建一个字典,其中键是元素,值是出现的次数。
fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
if fruit not in d:
d[fruit] = 0
d[fruit] += 1
使用.get()方法,你可以使这段代码更紧凑和清晰:
for fruit in fruits:
d[fruit] = d.get(fruit, 0) + 1
为什么dict.get(key)而不是dict[key]?
0. 总结
与dict[键]相比,dict。Get在查找键时提供一个回退值。
1. 定义
Get (key[, default])内置类型- Python 3.6.4rc1文档
如果key在字典中,则返回key的值,否则为default。如果没有给出default,则默认为None,因此该方法永远不会引发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. 问题解决了。
如果没有默认值,则必须编写繁琐的代码来处理此类异常。
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'
作为一个方便的解决方案,dict。Get引入了一个可选的默认值,避免了上述杂乱的代码。
3.结论
字典Get有一个额外的默认值选项,用于在字典中缺少key时处理异常
使用.get()时需要注意的一个问题:
如果字典包含调用.get()中使用的键,且其值为None,则.get()方法将返回None,即使提供了默认值。
例如,下面返回None,而不是'alt_value',这可能是预期的:
d = {'key': None}
assert None is d.get('key', 'alt_value')
.get()的第二个值仅在提供的键不在字典中时才返回,而不是在该调用的返回值为None时才返回。
有一个区别,这可能是一个优势,如果我们正在寻找一个不存在的键,我们将得到None,不像我们使用括号符号时,在这种情况下,我们将得到一个错误抛出:
print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'
get方法最后一个很酷的地方是,它接收了一个额外的可选参数作为默认值,也就是说,如果我们试图获取学生的分数值,但学生没有分数键,我们可以得到0。
所以与其这样做(或类似的事情):
score = None
try:
score = dictionary["score"]
except KeyError:
score = 0
我们可以这样做:
score = dictionary.get("score", 0)
# score = 0
另一个我没有看到提到的用例是作为sort, max和min等函数的key参数。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
感谢对不同问题的回答提供了这个用例!
其他回答清楚地解释了字典括号键控和.get之间的区别,并提到了一个相当无害的陷阱,当None或默认值也是一个有效键时。
有了这些信息,可能很容易得出这样的结论:. Get在某种程度上比方括号索引更安全更好,应该总是使用而不是方括号查找,就像在Python中停止使用方括号符号来获取字典的值中所争论的那样,即使在他们期望查找成功的常见情况下(即永远不会引发KeyError)。
博客文章的作者认为。get“保护你的代码”:
请注意,试图引用一个不存在的术语会导致KeyError。这可能会导致严重的问题,特别是在处理不可预测的业务数据时。 虽然我们可以用try/except或if语句来包装语句,但对字典术语的如此关注很快就会堆积起来。
确实,在不常见的情况下,null (None)-合并或以其他方式填充一个缺失的值来处理不可预测的动态数据,明智部署的.get是一个有用的python简化工具,用于dct:和try/except块中笨拙的if键,这些块仅存在于设置默认值时,键可能缺失,作为程序行为规范的一部分。
但是,用.get替换所有括号字典查找,包括那些断言必须成功的字典查找,则是另一回事。这种实践有效地降低了一类运行时错误,这些错误有助于将错误揭示为难以识别和调试的静默非法状态场景。
程序员常犯的一个错误是认为异常会引起头痛,并试图抑制它们,使用诸如在try…除了:传递块。他们后来意识到,真正令人头疼的是,在出现故障时从未发现应用程序逻辑被破坏,也从未部署过被破坏的应用程序。更好的编程实践是包含所有程序不变量的断言,例如必须在字典中的键。
错误安全的层次结构大致如下:
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. |
当编程语言设计者谈论程序安全性时,一个主要目标是通过将运行时错误提升为编译时错误,将静默逻辑错误提升为运行时异常或(理想情况下)编译时错误,来揭示而不是抑制真正的错误。
Python作为一种解释型语言,严重依赖于运行时异常而不是编译器错误。缺少方法或属性,非法类型操作,如1 + "a"和越界,或缺少索引或键会在默认情况下引发。
一些语言,如JS, Java, Rust和Go,在默认情况下为它们的映射使用回退行为(在许多情况下,不提供抛出/抛出替代方案),但Python默认抛出,以及其他语言,如c#。Perl/PHP发出未初始化值警告。
对所有字典访问不加区别地应用.get,即使是那些预计不会失败的访问,也没有处理None(或任何默认值)的回退方法,在代码中肆意地运行,这几乎破坏了Python对这类错误的运行时异常安全网,使潜在的错误变得沉默或间接。
偏爱方括号查找的其他支持原因(偶尔会在需要默认值的地方适当放置.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. 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. Testing increases in complexity in proportion to the new "legal" program paths permitted by .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). .get is a bit slower. .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). Minor.
一些语言,如c++和Ruby提供了替代方法(分别为at和fetch)来选择进入,从而在错误访问时抛出错误,而c#提供了选择进入的回退值TryGetValue,类似于Python的get。
由于JS、Java、Ruby、Go和Rust在默认情况下都将.get作为后备方法用于所有哈希查找,人们可能会认为,这并没有那么糟糕。的确,这并不是语言设计者面临的最大问题,而且无抛出访问版本有很多用例,所以没有跨语言的共识也就不足为奇了。
但正如我所说,Python(以及c#)通过将assert选项作为默认选项,比这些语言做得更好。在出现故障时,不使用它来报告合同违规行为,而不加区别地使用。get,是一种安全性和表达性的损失。
它允许您提供一个默认值,而不是在没有找到该值时得到一个错误。像这样的劝说代码:
class dictionary():
def get(self,key,default):
if self[key] is not found :
return default
else:
return self[key]
简短的回答
方括号用于条件查找,当缺少键时,条件查找可能会失败并返回KeyError。
get()方法用于无条件查找,这种查找永远不会失败,因为已经提供了默认值。
基本方法和辅助方法
方括号调用__getitem__方法,这是字典等映射的基础。
get()方法是在该功能之上分层的帮助器。它是通用编码模式的捷径:
try:
v = d[k]
except KeyError:
v = default_value
在Python 3.8及以后版本中,字典get()方法可以与赋值表达式中的walrus操作符:=一起使用,以进一步减少代码:
if (name := dictonary.get("Name")) is not None
return name
使用[]而不是get()将需要将代码包装在try/except块中并捕获KeyError(未显示)。如果没有walrus操作符,您将需要另一行代码:
name = dictionary.get("Name")
if (name is not None)
return name