程序员文章、书籍推荐和程序员创业信息与资源分享平台

网站首页 > 技术文章 正文

有用的 Python 提示和技巧 — #2

hfteth 2024-12-13 11:53:37 技术文章 18 ℃

1 — 带循环的 else 条件语句

可以将 else 语句与 for/while-loop 一起使用,以便在循环终止时执行代码,而不管是否执行了循环。查看代码:

Bash
items = [1, 2]

for item in items: 
    print(item) 
else: # if no break is found 
    print("No Break") 

Else 块将在循环完全完成时执行。

例如,假设需要在列表中搜索某些内容并处理每个项目,直到找到条件。

Bash
items = [1, 2]

for item in items:   
    if item % 2 == 0:
      break

    do_something(item)
else:
    do_another_something()

如果找到条件,则需要使用 break 语句来中断循环并直接转到 else 块。

相同的语句对 while-loop 有效:

while False:
  ...
else:
  print("No Break") 

使用此功能有点令人困惑。我从未见过有人在项目中使用它,而且它可能不经常使用。

2 — 在 pytest 中参数化测试函数

parametrize 是一个 Pytest 标记装饰器,用于使用不同的参数集多次执行相同的测试函数。请参阅示例:

import pytest


params = [
    (1, 2, 3), 
    (2, 4, 6), 
    pytest.param(6, 9, 16, marks=pytest.mark.xfail)
]

@pytest.mark.parametrize("p1, p2, ,expected", params)
def test_func(p1, p2, expected):
    assert p1 + p2 == expected

第三组参数使用 xfail 标记来定义 failure 参数。我鼓励您阅读有关 mark test 函数的更多信息。

3 — 使用嵌套循环的列表推导式

要了解嵌套循环在列表推导式中的工作原理,请参阅以下代码:

letters = ["a", "b", "c"]
numbers = [1, 2]

for letter in letters:
  for number in numbers:
    print(f"{letter}{number}")

>> ['a1', 'a2', 'b1', 'b2', 'c1', 'c2']

同样的行为可以用 comprehension 来执行:

letters = ["a", "b", "c"]
numbers = [1, 2]

combined_items = [l+str(n) for l in letters for n in numbers]
combined_items

>> ['a1', 'a2', 'b1', 'b2', 'c1', 'c2']

理解是一种避免嵌套循环在单行代码中组合多个 for 循环的方法。

4 — 使用 tqdm 在循环上迭代

tqdm 是一个 Python 库,它提供了一种向循环添加进度条的简单方法。建议用于长时间运行的进程,以向用户显示有关进度状态的视觉提示。

from tqdm import tqdm


paths = os.walk('/')

for fpath in tqdm(paths, desc="Looping over root dir"):
    ...

desc 参数可用于设置循环的描述。

5— 泛型函数

泛型函数是一种机制,它允许函数使用多种类型来操作相同的行为,以维护它们之间的关系,例如参数、名称和返回值。请参阅以下示例:

import functools


@functools.singledispatch
def process_data(data):
    print("Generic processing:", data)

@process_data.register(int)
def _(data):
    print("Processing integer data:", data)

@process_data.register(list)
def _(data):
    print("Processing list data:", data)

process_data("Hello")    # Generic processing: Hello
process_data(42)         # Processing integer data: 42
process_data([1, 2, 3])  # Processing list data: [1, 2, 3]

另一方面,你可以使用定义类型提示的泛型函数,例如:

import functools

@functools.singledispatch
def process_data(address):
    raise TypeError('Wrong address format!')

@process_data.register
def _(address: str):
    ip, port = address.split(':')
    print(f'IP:{ip}, Port:{port}')

@process_data.register
def _(address: tuple):
    ip, port = address
    print(f'IP:{ip}, Port:{port}')

process_data('johni.medium.com:443')     # johni.medium.com, Port:443
process_data(('johni.medium.com', 443))  # johni.medium.com, Port:443
process_data(2077)                       # TypeError: Wrong address format!

类型提示方法听起来更优雅、可读性更强。

6 — 使用 PyPi 测试存储库

PyPi Test 是用于测试目的的 PyPi 存储库版本。它可用于练习和学习如何在发布包之前将其发布到 Python 生态系统。

  • 官方主办方
  • 使用 TestPyPI

PyPi Test 具有独立于 PyPi 存储库的数据库,您需要创建一个单独的用户帐户来发布您的软件包。

7 - 使用上下文管理器

上下文管理器是一种管理资源的方法。您可以在不再需要资源时自动设置和关闭资源。

要使用上下文管理器,您需要创建一个具有两个特殊方法的类:当输入代码块并用于返回资源实例时调用 __enter__(),以及当退出代码块时调用 __exit__()。

class MyContextManager:
  def __enter__(self):
    resource = object()
    return resource

  def __exit__(self, exe_type, exe_value, traceback):
    # clearn up the resource
    ...

# using the context manager
with MyContextManager() as cx:
  print(cx)

要将上下文管理器与生成器一起使用,您需要定义一个函数并使用 yield 语句返回实例。退出代码块时,将执行 yield 语句后面的代码。


@contextmanager
def my_context_manager():
  resource = object()
  try:
    yield resource
  finally:
    # clean up the resource
    ...


with my_context_manager() as cx:
  print(cx)

上下文管理器是一种管理代码中资源的特殊方法,例如文件处理、网络连接和数据库连接。

8 — 定时

计时是一种测量一段代码执行时间的方法。它对于快速检查部分代码的性能非常有用。

time它是一个内置的 Python 模块,它提供了一种简单的方法来运行一段代码来获取执行时间。让我们检查一个使用三引号的示例:

import timeit


setup = """
import random
import string
"""
stmt = """ 
def get_random_token(n_lenght: int) -> str:
    chars = string.ascii_uppercase + string.digits
    token = ''.join(random.choice(chars) for _ in range(n_lenght))
    return token
get_random_token(100)
"""
times = timeit.repeat(stmt=stmt, setup=setup, repeat=2, number=1000)
print(times)

您还可以在命令行 python-m timeit --n [number] -s [setup] [stmt] 中使用 timeit

9— 海象操作员

从 Python 3.8 开始,您可以使用称为 walrus 运算符 (:=) 的特殊赋值表达式。此 sintaxe 允许您为 expression 中的变量赋值并使用它。请参阅以下示例:

while (value := input('Type something: ')) != 'exit':
    print(value)
entries = [
    {
        "name": "Lisa",
    },
    {
        "name": "",
    },
]

for entry in entries: 
    if name := entry.get("name"):
        print(f'Found name: "{name}"')
numbers = [1,2,4,5,6,6,89]

if (length := len(numbers)) >= 5:
    print("The length of the list is:",length)

使用 walrus 运算符不一定能提高代码的可读性或效率,在某些情况下,最好以传统方式编写代码。

10 – 使用入口点

入口点是程序执行开始的显式函数。它在 Java 和 CSharp 等语言中很常见。

在 Python 中,不需要使用入口点函数,但建议您使用它来使您的代码更具可读性和直观性。

def main() -> None:
    ... # do something


if __name__ == '__main__':
    main()

这是一个在 Python 项目中使用的有趣入口点函数

最近发表
标签列表