有人能看完这段Python代码并给我解释一下吗
上面是python代码,它创建了一个月的列表,基本上打印用户输入的内容,如果它是有效月还是无效月。上面的代码很好 下面是与上面类似的另一个版本,但我想更好或者更方便用户。但我不确定它到底是如何工作的,我还没有看到python字典以这种方式出现。有人能看完这段代码并向我解释一下吗?非常感谢有人能看完这段Python代码并给我解释一下吗,python,Python,上面是python代码,它创建了一个月的列表,基本上打印用户输入的内容,如果它是有效月还是无效月。上面的代码很好 下面是与上面类似的另一个版本,但我想更好或者更方便用户。但我不确定它到底是如何工作的,我还没有看到python字典以这种方式出现。有人能看完这段代码并向我解释一下吗?非常感谢 months = ['January', 'February', 'March', 'April', 'May',
months = ['January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December']
def valid_month(month):
if month:
cap_month = month.capitalize()
if cap_month in months:
return cap_month
这更有效的原因是dict
使用哈希集作为其内部表示,因此查找其中是否存在键是一个(分期)O(1)操作,而对大小为n的列表执行相同操作是最坏情况下的O(n)操作
根据@abarnert的评论,这也使得编写代码更加方便用户,因为您只需执行
dict.get(key)
,而不必担心代码中的迭代逻辑。条件变成了“真/假”问题,而不是“此集合中的任何一种情况都是真的[…]?”它可能有助于打印出您从该额外步骤中得到的信息:
months_abbvs = dict((m[:3].lower(), m) for m in months)
# months_abbvs = { 'jan':'January', 'feb':'February',... }
# the actual operation is two-step:
# 1. [(m[:3].lower(),m) for m in months] list comprehension over the "months" list which:
# 1.1. [m[:3].lower()] take first three letters of each item in the list, apply lowercase()
# 1.2. [(m[:3].lower,m)] return a tuple of (1.1, item)
# 2. [dict(...)] build a dictionary from the list comprehension
# 2.2. for each tuple returned from (1.2), create a key:value pair in the dict
def valid_month(month):
if month:
short_month = month[:3].lower()
# get first three letters as lowercase string
return month_abbvs.get(short_month)
# 1. [month_abbvs.get(short_month)] perform dict.get(key)
# 2. return result of 1 (None if no such key exists)
因此,您有一个小写缩写到完整月份名称的映射
这是怎么回事?首先,让我们看一下表达式的作用:
>>> months_abbvs
{'apr': 'April',
'aug': 'August',
'dec': 'December',
'feb': 'February',
'jan': 'January',
'jul': 'July',
'jun': 'June',
'mar': 'March',
'may': 'May',
'nov': 'November',
'oct': 'October',
'sep': 'September'}
因此,每个月的理解都是这样的:
>>> m = 'December'
>>> m[:3].lower()
'dec'
>>> m[:3].lower(), m
('dec', 'December')
如中更详细的解释,理解基本上是循环的简写。特别是,这:
>>> [(m[:3].lower(), m) for m in months]
[('jan', 'January'),
('feb', 'February'),
('mar', 'March'),
('apr', 'April'),
('may', 'May'),
('jun', 'June'),
('jul', 'July'),
('aug', 'August'),
('sep', 'September'),
('oct', 'October'),
('nov', 'November'),
('dec', 'December')]
更好的是,不要反复编写m[:3].lower()
,给它起个好名字并使用它:
months_abbvs = {m[:3].lower(): m for m in months}
然后:
def abbreviate(m):
return m[:3].lower()
months_abbvs = {abbreviate(m): m for m in months}
现在,您对新版本中的输入所做的是:
def valid_month(month):
if month:
short_month = abbreviate(month)
return month_abbvs.get(short_month)
由于month\u abvs
是一个dict
(您可以通过打印出来,或者仅仅从它是通过调用dict
在某个东西上创建的这一事实来判断),因此get
方法是有效的。因此,正如链接文档中所解释的,month\u abvs.get(short\u month)
与months\u abvs[short\u month]
相同,只是如果未找到键short\u month
,您将获得None
,而不是引发异常
因此,如果给定“十月”
,您将short\u month
设置为“十月”
。然后在缩写词典中查找,它返回“十月”
。如果给定了'OCT'
或'octor'
或'octal digital string'
,您也将返回相同的内容。由于任何非空字符串都是真实的,如果您执行了类似于if valid_month('十月'):
的操作,那么它将是真实的
但是,如果给定,比如说,'Muhammed'
,您将short\u month
设置为'muh'
。然后你查了一下,它不在那里。如上所述,对于未知键,get
方法返回None
,因此您将返回None
。因为None
是错误的,如果你做了像if valid\u month('Muhammed'):
这样的事情,它就不会是正确的
换言之,它使函数更加宽松,这可能是一种改进,也可能是一件坏事(或者两者兼而有之,也许你希望
'OCT'
工作,但不是'octal digital string'
)。其他两个问题详细解释了代码的工作原理,但我想提请您注意代码设计的一个特殊方面:它有避免异常的测试,如果这些测试失败,代码将停止执行,这样执行将从函数文本的末尾开始,并返回None
编写代码的一种更简单的方法是消除检查并处理异常:
short_month = month[:3].lower()
return month_abbvs.get(short_month)
变成:
def valid_month(month):
if month:
# this will raise an exception if month is not a string
short_month = month[:3].lower()
return month_abbvs.get(short_month)
def valid_month(month):
if month:
cap_month = month.capitalize()
if cap_month in months:
return cap_month
这给了我们一条主线去理解,在这种情况下更容易理解。显然,检查越多,这给我们的简单性就越高
变成:
def valid_month(month):
if month:
# this will raise an exception if month is not a string
short_month = month[:3].lower()
return month_abbvs.get(short_month)
def valid_month(month):
if month:
cap_month = month.capitalize()
if cap_month in months:
return cap_month
在这种情况下,这并不能给我们带来很多好处。能够同时使用这两种样式很好。在第一段代码中,月份是一个列表,而不是一个字典。我不认为效率与此相关。这一变化是对函数语义的一个重大变化,其目的显然是使其“更加用户友好”,因此语义而不是性能才是最重要的。此外,如果性能才是最重要的,那么它会简单得多,速度也会快得多,也不能仅仅将
months
更改为set
,方法是用大括号替换方括号,其他内容保持不变。@abarnert同意。我猜问题中的代码来自某个在线课程。。。我还猜测(可能是错误的?)问题是问“这段代码中发生了什么?”而不是为什么,因此代码部分出现了故障。它很粗糙,但我认为它准确地描述了过程本身。你的新编辑说“你只需做一个dict.get(key)
,而不必担心迭代逻辑”…但他的原始版本也不担心迭代逻辑;它只是在几个月内做了一次cap\u月检查。所以,这个评论是错误的。谢谢。这实际上非常有用。这是不对的month_abvs.get(…)
永远不会引发keyrerror
。除非month
不是一个序列,否则任何东西都不会产生AttributeError
,这与if month:
的测试完全不同,后者测试(除其他外)空字符串。@abarnert trymonth=['foo';month.capitalize()
并告诉我您得到了什么。@Marcin:是的,除了跳过他以前做的一些测试之外,您还为他最初的代码没有测试的完全不同的问题添加了测试。在month\u abvs.get(短\u month)中get方法从何而来另外,你能简单地解释一下你不熟悉的整个理解概念是如何运作的吗here@muhammed:我将编辑答案进行解释,并添加一些链接。谢谢你澄清了你需要解释的部分。
def valid_month(month):
try:
return month_abbvs.get(month[:3].lower())
except KeyError, AttributeError: # or Exception to catch everything
return None
def valid_month(month):
if month:
cap_month = month.capitalize()
if cap_month in months:
return cap_month
def valid_month(month):
try:
cap_month = month.capitalize()
if cap_month and cap_month in months:
return cap_month
except AttributeError:
return None