Python 技巧 - 黑魔法 - 第一部分

发布日期:2026-07-19 09:10:04  来源 : 杭州电子商务研究院    浏览量 :0
杭州电子商务研究院 发布日期:2026-07-19 09:10:04  
0

介绍

编者注:本指南是实用 Python 技巧系列的一部分。阅读有关本系列的更多信息并在此处找到其他指南的链接。

在本指南中,我们将开始学习一些不常见的 Python 高级技巧。这些技巧包括一些我称之为“黑魔法”的神奇技巧。每个 Python 技巧都分两个步骤进行解释:

  1. 概念的简要描述和交互式代码示例
  2. 一些鼓舞人心的例子来启发你

黑魔法的解释

本指南涵盖了一些不常见的技巧,其中很多技巧可能会产生副作用。但这些技巧真的很酷,在特定场景中发挥着神奇的作用——所以我称它们为 Python 世界中的“黑魔法”。由于场景限制和副作用,它们的主要作用是打开你的思路,点亮你的灵感,提升你的 Python 能力。

一旦您权衡了利弊并知道如何正确使用它们,其中一些可能会成为您代码的一部分。

东亚足联

这篇文章《惯用的 Python:EAFP 与 LBYL》很好地阐述了 EAFP 与 LBYL 的区别:

EAFP(请求原谅比请求许可更容易)意味着您应该只做您期望做的事情,如果操作可能引发异常,那么捕获它并处理这个事实。

LBYL(三思而后行)是指首先检查某件事是否会成功,并且只有确定它会成功时才继续进行。

      """LBYL"""
if "key" in dict_:
    value += dict_["key"]
    
"""EAFP"""
# downplays the importance of the key
try:
    value += dict_["key"]
except KeyError:
    pass
    

这遵循了 Python 的设计理念:“显式优于隐式”。

EAFP 在 Python 中的表现也是可以接受的:

但是由于异常用于控制流(如在 EAFP 中),Python 实现会努力使异常成为一种廉价的操作,因此您在编写代码时不必担心异常的成本。

与其他黑魔法不同,这是 Python 中推荐的编码风格。

EAFP 是Python 中合法的编码风格,当它有意义时你可以随意使用它。

让我们用 Pythonic 风格编写一个斐波那契示例。我们将使用生成器提供结果并以 EAFP 风格进行迭代。

      """pythonic fibonacci"""
# generator function
def fibonacci(n):
    a, b, counter = 0, 1, 0
    while counter <= n:
        yield a
        a, b = b, a + b	# multiple assignment
        counter += 1
        
f = fibonacci(5)
# EAFP
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        break
# output: 0 1 1 2 3 5
    

鼓舞人心的例子

      """used in detect cycle in linked list"""
# L141: determine there is a cycle in a linked list
def has_cycle_in_linked_list(head: ListNode) -> bool:
    try:
        slow = head
        fast = head.next
        while slow is not fast:
            slow = slow.next
            fast = fast.next.next
        return True
    except:
        return False

"""used in binary search and insert"""
# L334: given an unsorted array return whether an increasing subsequence (incontinuous) of length k exists or not in the array.
def increasing_triplet(nums: List[int], k: int) -> bool:
    try:
        inc = [float('inf')] * (k - 1)
        for x in nums:
            inc[bisect.bisect_left(inc, x)] = x
        return k == 0
    except:
        return True

"""used in eval"""
# L301: Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.
def remove_invalid_parentheses(s: str) -> List[str]:
    def isvalid(s):
        try:
            eval('0,' + ''.join(filter('()'.count, s)).replace(')', '),'))
            return True
        except:
            pass
    level = {s}
    while True:
        valid = list(filter(isvalid, level))
        if valid:
            return valid
        level = {s[:i] + s[i+1:] for s in level for i in range(len(s))}
    

自助

这是动态属性的一个技巧。成本有点高,因为它会污染原始结构。

鼓舞人心的例子

使用自身作为链接列表中的虚拟节点。

      """reuse self to save the cost of dummy node"""
def traverse_linked_list(self, head: TreeNode) -> TreeNode:
    pre, pre.next = self, head
    while pre.next:
        self.process_logic(pre.next)
    return self.next  # return head node
    

评估

eval()将任意字符串作为 Python 代码执行。但请注意,eval可能会成为潜在的安全风险。

鼓舞人心的例子

构建树构造函数并使用eval执行。

      # L536: construct binary tree from string
def str2tree(s: str) -> TreeNode:
    def t(val, left=None, right=None):
        node, node.left, node.right = TreeNode(val), left, right
        return node
    return eval('t(' + s.replace('(', ',t(') + ')') if s else None
    

str.查找

这是str.find的一个巧妙用法,虽然这个用法不太具有普遍性,但是思路还是可以借鉴的。

鼓舞人心的例子

我们使用find来构建一种机制:如果val是 '#' 则返回 1,如果不是则返回 -1。

      # L331: verify preorder serialization of a binary tree, if it is a null node, we record using a sentinel value #
def is_valid_serialization(preorder: str) -> bool:
    need = 1
    for val in preorder.split(','):
        if not need:
            return False
        need -= ' #'.find(val)
    return not need
    

字符串替换

使用str.replace实现字符串版本的并查集(不相交集)。

鼓舞人心的例子

与普通的 union-find 相比,这个字符串版本简洁,优雅,高效。

      """convert int to unicode char, and use str.replace to merge the connected nodes by reduce"""
# L323: given n nodes from 0 to n - 1 and a list of undirected edges, find the number of connected components in an undirected graph.
def count_connected_components(n: int, edges: List[List[int]]) -> int:
    return len(set(reduce(lambda s, edge: s.replace(s[edge[1]], s[edge[0]]), edges, ''.join(map(chr, range(n))))))
    

^ (异或)

^通常用于删除完全相同的数字并保留奇数,或者保留不同的位并删除相同的位。

鼓舞人心的例子

这些例子说明了^的一些令人惊奇的用法。

      """Use ^ to remove even exactly same numbers and save the odd, or save the distinct bits and remove the same."""
"""bit manipulate: a^b^b = a"""
# L268: Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.
def missing_number(nums: List[int]) -> int:
    res = 0
    for i, e in enumerate(nums):
        res = res ^ i ^ e
    return res ^ len(nums)

"""simply find the first index whose "partner index" (the index xor 1) holds a different value."""
# L540: find the single element, in a sorted array where every element appears twice except for one. 
def single_non_duplicate(nums: List[int]) -> int:
    lo, hi = 0, len(nums) - 1
    while lo < hi:
        mid = (lo + hi) // 2
        if nums[mid] == nums[mid ^ 1]:
            lo = mid + 1
        else:
            hi = mid
    return nums[lo]

"""parity in triple comparisons"""
# L81: search a target in a rotated sorted array
def search_in_rotated_sorted_arr(nums: List[int], target: int) -> int:
    """I have three checks (nums[0] <= target), (target <= nums[i]) and (nums[i] < nums[0]), and I want to know
    whether exactly two of them are true. They can't all be true or all be false (check it), so I just need to
    distinguish between "two true" and "one true". Parity is enough for that, so instead of adding them I xor them"""
    self.__getitem__ = lambda i: (nums[0] <= target) ^ (nums[0] > nums[i]) ^ (target > nums[i])
    i = bisect.bisect_left(self, True, 0, len(nums))
    return i if target in nums[i:i+1] else -1
    

结论

在本指南中,我们学习了一些 Python 黑魔法技巧,例如 EAFP、eval、xor 以及一些内置函数的高级技巧。我希望其中一些对你有用。

第 2 部分中,我们将继续学习其他 Python 黑魔法技巧。您还可以从 Github下载示例笔记本black_magics.ipynb 。

本指南是 Python 技巧指南系列之一:

希望你喜欢。如果您有任何问题,欢迎通过 recnac@foxmail.com 与我联系。

以上内容来自杭州电子商务研究院推送
分享到:

长按或扫码识别 分享给好友

长按或扫码识别 分享给好友
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据