图片

本文约2000字,建议阅读5分钟
本文介绍了5个在多数 Python 教程中较少提及、但能高效解决实际问题的实用特性。

今天跟大家介绍的这几个功能,并不是像你平时看到的那种“隐藏在显而易见的地方”的功能,而是需要对Python源代码有一定的专研,而后才能发现这些特性。

今天我们选择了5 个 Python 特性,这些特性在大部分教程中很少提及,但却能解决非常实际的问题— — 并且做得干净利落,没有任何多余的内容,样板代码也很少。

接下来就跟我们一起看看吧~

1.contextlib.suppress:悄悄地kill异常


问题:你想要忽略一个非常具体的异常,但try/except仅为了这一点而编写块却感觉有点大材小用。

你可以这样写:

try:    os.remove('tempfile.txt')except FileNotFoundError:    pass

或者你可以这样写——优雅的、Pythonic 的、 Jedi 的方式:

from contextlib import suppresswith suppress(FileNotFoundError):    os.remove('tempfile.txt')

就是这样。

没有try,没有except,没有pass。只是清晰易读的意图:


“我想运行这个程序。如果发生这个特定的错误,请悄悄地继续运行。”

何时使用:

  • 删除文件或关闭套接字

  • 清理临时文件

  • 关闭可能不存在的服务

你甚至可以抑制多个异常。

with suppress(FileNotFoundError, PermissionError):    os.remove('config.yaml')

这种功能可以让你的代码变得 10 倍简洁 — — 而且它隐藏在contextlib大多数人只会接触的模块深处@contextmanager。


2.sys.setrecursionlimit: 在递归攻击你之前先破解它


你正在编写一个递归算法 — — 比如树遍历或 DFS — — 然后 Python 突然放弃了:

RecursionError: maximum recursion depth exceeded

这是因为 CPython 的默认递归限制保守为1000。

大多数教程不会告诉你的是:你可以提高这个限制——只需一行代码即可。

import syssys.setrecursionlimit(10**6)

完全有效的递归代码中不再出现奇怪的堆栈溢出。

何时使用:

  • 自定义解析器

  • 递归数据结构遍历

  • 回溯算法

专业提示:除非你了解程序的调用堆栈深度,否则请勿随意将其设置过高。每次调用都会占用内存。但如果你知道自己在做什么,这将带来显著的改变。

因为大多数人都害怕触碰sys设置,所以你经常回忽略他。

3. typing.Literal:安全字符串的秘诀


你有一些函数可以接受字符串,但实际上它们只接受几个有效值。像这样:

def connect(mode: str):    if mode not in ['read', 'write']:        raise ValueError("Invalid mode")

这没问题,但这是运行时验证。为什么不把它转移到类型检查器呢?

进入Literal:

from typing import Literaldef connect(mode: Literal['read', 'write']):    ...

现在,如果你传递除'read'或'write'之外的任何内容,你的 IDE 或静态类型检查器(如mypy)甚至会在你运行代码之前尖叫。

def get_user(role: Literal['admin', 'moderator', 'user']):    ...

这使得你的 API 具有自文档性、安全性和健壮性— — 无需编写if块或自定义验证器。

这是动态语言中简洁的编译时验证。而且,它与pydantic、FastAPI和现代工具完美兼容。

Bonus Flex:也适用于Union:

def get_data(format: Literal['json', 'xml'] | None = None):    ...

4.__missing__:dict子类中被低估的魔法方法


你正在使用字典并想要自定义如何处理丢失的键 - 但defaultdict没有给你足够的控制权。

是时候覆盖支持这一切的隐藏方法了:__missing__。

class AutoDict(dict):    def __missing__(self, key):        value = self[key] = f"[{key} not found]"        return value

用法:

d = AutoDict()print(d['python'])    # [未找到python] print(d['java'])    # [未找到java]

这里发生了什么?


当找不到某个键时,__missing__就会触发。你可以记录、转换、回退,甚至自动插入值。

高级用例:
跟踪未知的访问模式:

class AccessTracker(dict):    def __missing__(self, key):        print(f"Key {key} accessed but not found.")        raise KeyError(key)

重要性:


它让你能够对字典行为进行精准的控制。大多数开发者甚至不知道__missing__的存在——除了官方的 Python 数据模型参考之外,它通常没有相关的文档。

5. __subclasshook__:让你的 API 更加安全


你已经定义了一个抽象基类,但你不想强迫人们从它继承 -- 你只是希望他们实现正确的方法。

Python 将此称为结构类型— — 这就是你会喜欢__subclasshook__的原因。

from abc import ABC, abstractmethodclass JsonSerializable(ABC):    @abstractmethod    def to_json(self):        pass    @classmethod    def __subclasshook__(cls, C):        if any("to_json" in B.__dict__ for B in C.__mro__):            return True        return NotImplemented

现在,如果一个类有一个to_json()方法——无论是否继承——它都会被视为子类。

class MyClass:    def to_json(self):        return '{"hello": "world"}'print(issubclass(MyClass, JsonSerializable))  # True

无需强制继承,即可获得类似接口的行为。这在构建插件、API或框架时非常有用——灵活性胜过僵化的层次结构。

编辑:于腾凯

校对:林亦霖

关于我们

数据派THU作为数据科学类公众号,背靠清华大学大数据研究中心,分享前沿数据科学与大数据技术创新研究动态、持续传播数据科学知识,努力建设数据人才聚集平台、打造中国大数据最强集团军。

图片

新浪微博:@数据派THU

微信视频号:数据派THU

今日头条:数据派THU

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐