社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

8个重构技巧使得Python代码更Pythonic

数据STUDIO • 1 年前 • 240 次点击  

1.合并追加到列表声明

我们从一个简单的开始。不是声明一个空列表然后附加到它,而是直接用所有元素初始化列表。这缩短了代码并使意图更加明确。它的性能也稍微好一些,因为它避免了对 append() 的函数调用。

players = []
players.append("Patrick")
players.append("Max")
players.append("Jessi")

# -> refactor
players = ["Patrick""Max""Jessi"]

这同样适用于填充其他集合类型,如集合和字典。

2 使用items()直接解包字典值

当遍历字典时,你需要键和值,那么不要手动访问值。而是迭代dictionary.items(),它同时为你提供键和值。

这节省了我们过去分配给 players 的行,代码现在读起来更自然,重复更少。

teams_by_color = {"blue": ["Patrick""Jessi"]}

for team_color in teams_by_color:
    players = teams_by_color[team_color]
    if is_winning(team_color):
        advance_level(players)

# -> refactor
for team_color, players in teams_by_color.items():
    if is_winning(team_color):
        advance_level(players)

3. 将 range(len) 替换为枚举

如果我们需要遍历列表并且需要同时跟踪索引和当前项,请使用内置enumerate()函数而不是range(len)。这会将当前索引和当前项目作为元组返回。所以我们可以直接在这里查看值,也可以访问带有索引的项目。

for i in range(len(players)):
    print(i, players[i])

# -> refactor
for i, player in enumerate(players):
    print(i, player)

Enumerate 还带有一个可选的start参数。如果你使用它,计数器将从该值开始。但请注意,这些项目仍然从第一个开始。

for i, player in enumerate(players, start=1):
    print(i, player)

4. 用枚举调用替换手动循环计数器

这与之前非常相似。有时我会看到直接对项目执行迭代的代码——这本身并不坏——但随后需要一个计数器,它会在循环内手动递增。同样在这里你可以简单地使用 enumerate 函数。这更简单,也更快。

i = 0
for player in players:
    print(i, player)
    i += 1

# -> refactor
for i, player in enumerate(players):
    print(i, player)

4.1 不要手动更新计数器

如果你只需要计算项目的数量,也不要遍历循环并手动计算所有项目。相反,只需使用len()函数来获取列表中的元素数。

num_players = 0
for player in players:
    num_players += 1

# -> refactor
num_players = len(players)

5.将条件简化为return语句

当我们到达一个方法的末尾并想要返回 TrueFalse 时,一种常见的做法是这样的。如果条件为 True,我们返回 True。否则我们最后返回 False。然而,直接返回结果更简洁:

def function():
    if isinstance(a, b) or issubclass(b, a):
        return True
    return False

# -> refactor
def function():
    return isinstance(a, b) or issubclass(b, a)

我们在这里应该注意的一件事是,只有当表达式的计算结果为布尔值时才能这样做。isinstance()issubclass()都是返回布尔值的函数,所以这很好。但在下一个示例中,第一个表达式pythonistas是一个列表而不是布尔值。

如果pythonistas是一个有效的非空列表,这将返回列表而不是预期的布尔值,然后可能是你的应用程序中的错误。因此,为了确保我们在这里返回一个布尔值,我们可以将返回包装在对 bool()函数的调用中。

def any_pythonistas():
    pythonistas = [coder for coder in coders if is_good_in_python(coder)]
    if pythonistas or self.is_pythonista():
        return True
    return False

# -> refactor
def any_hats():
    pythonistas = [coder for coder in coders if is_good_in_python(coder)]
    return bool(pythonistas or self.is_pythonista())

6.合并条件中的重复块

我们应该始终寻找机会删除重复的代码。这样做的好地方是if …elif链中有多个相同的块。

在此示例中,ifelif 都导致相同的执行功能。所以我们可以使用or组合前两个块来删除对函数的重复调用。现在,如果我们需要更改process_standard_payment()行,我们可以在一处而不是两处进行。

def process_payment(payment, currency):
    if currency == "USD":
        process_standard_payment(payment)
    elif currency == "EUR":
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

# -> refactor
def process_payment(payment, currency):
    if currency == "USD" or currency == "EUR":
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

7.用in运算符替换同一个变量的多次比较

我们甚至可以进一步重构以前的代码。由于我们针对多个值重复检查同一个变量,我们可以使用 in 运算符来缩短它。如果货币值在定义的列表中,我们将执行专用操作。

def process_payment(payment, currency):
    if currency == "USD" or currency == "EUR":
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

# -> refactor
def process_payment(payment, currency):
    if currency in ["USD""EUR"]:
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

为了再次改进这一点,我们应该在这里使用一个集合。在集合中查找值更快,而且无论如何我们都想要这里的唯一元素,所以集合是更好的选择。

# -> refactor
def process_payment(payment, currency):
    if currency in {"USD""EUR"}:
        process_standard_payment(payment)
    else:
        process_international_payment(payment)

8. 将 for 循环中的 yield 替换为 yield from

如果你已经熟悉生成器,那么这是一个高级技巧。一个经常被忽略的小技巧是 Python 的 yield 关键字对于可迭代对象有一个对应的yield from

如果你有一个像列表这样的可迭代对象,而不是说for item in iterable: yield item,你可以简单地说yield from iterable。这更短,并且消除了对可迭代对象的手动循环,这也可以提高性能。

def get_content(entry):
    for block in entry.get_blocks():
        yield block

# -> refactor
def get_content(entry):
    yield from entry.get_blocks()

🏴‍☠️宝藏级🏴‍☠️ 原创公众号『数据STUDIO』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括可戳👉 Python MySQL数据分析数据可视化机器学习与数据挖掘爬虫 等,从入门到进阶!

长按👇关注- 数据STUDIO -设为星标,干货速递

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/161853
 
240 次点击