有人可以通过这个Python代码并向我解释

时间:2013-09-05 19:35:18

标签: python

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

所以上面是创建月份列表的python代码,基本上打印用户输入的内容,如果它是有效的月份。上面的代码很好。

下面是另一个类似于上面的版本,但我想更好或更用户友好。但我不确定这是如何工作的我没有看到这种方式的python词典,有人可以通过这个代码解释给我,非常感谢。

months_abbvs = dict((m[:3].lower(), m) for m in months)

def valid_month(month):
    if month:
        short_month = month[:3].lower()
        return month_abbvs.get(short_month)

3 个答案:

答案 0 :(得分:5)

打印出从额外步骤中获得的内容可能会有所帮助:

>>> 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')]

正如the tutorial中更详细解释的那样,理解基本上是一个循环的简写。特别是:

>>> m2 = [<expression with m> for m in months]

......相当于:

>>> m2 = []
>>> for m in months:
...     m2.append(<expression with m>)

使用生成器表达式而不是列表推导意味着将序列构建为惰性迭代器而不是列表。

然后将结果(无论哪种方式)传递给dict构建一个字典,将每个元组的第一个值映射到第二个。


你可以把它作为字典理解来更可读地写出来:

months_abbvs = {m[:3].lower(): m for m in months}

更好的是,不要反复写m[:3].lower(),而是给它一个好名字并使用它:

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)

现在,您在新版本中对输入所做的是:

short_month = month[:3].lower()
return month_abbvs.get(short_month)

由于month_abbvsdict(您可以通过打印出来,或者仅仅是通过在某些内容上调用dict来创建它),{{1}方法是dict.get。因此,如链接文档中所述,getmonth_abbvs.get(short_month)相同,但如果找不到密钥months_abbvs[short_month],则会获得short_month,而不是提高None例外。

因此,如果给定'October',则会将short_month设置为'oct'。然后在缩写词典中查找,返回'October'。如果给定'OCT''october''octal digit string',您也会返回相同的内容。由于任何非空字符串都是真实的,如果你做过类似if valid_month('October'):的事情,那就是真的。

但是,如果给出'Muhammed',则会将short_month设置为'muh'。然后你看起来,它不存在。如上所述,get方法会针对未知密钥返回None,因此您将返回None。由于None是假的,如果你做过类似if valid_month('Muhammed'):的事情,那就不是真的了。

换句话说,它使功能更加宽松 - 这可能是一种改进,或者可能是一件坏事(或者可能是两者兼而有之 - 可能你想要'OCT'工作,但不是{{} 1}})。

答案 1 :(得分:2)

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)

这更有效的原因是dict使用哈希集作为其内部表示,因此查找是否存在密钥是(摊销的)O(1)操作,而执行相同操作列表是大小为n的列表的最坏情况O(n)操作。

根据@ abarnert的评论,这也使代码更加用户友好,因为您只需执行dict.get(key)而不必担心代码中的迭代逻辑。这个条件变成了“真/假”的问题,而不是“这个集合中的任何一个案例都是真的吗?”

答案 2 :(得分:0)

另外两个问题详细解释了代码是如何工作的,但我想提请你注意代码设计的一个特定方面:它有避免异常的测试,如果那些测试失败,代码停止执行,使执行从函数文本的末尾开始,然后返回None

编写代码的一种更简单的方法是消除检查,并处理异常:

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):
    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

在这种情况下,我们不会非常买我们。能够使用这两种风格是很好的。