Python 技巧 - 基础 - 第二部分

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

介绍

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

这是两篇有关 Python 基本技巧的指南中的第二篇。在第一篇中,我们学习了许多有用的 Python 基本技巧。如果您错过了,请查看这篇。

在本指南中,我们将继续向我们的技能库中添加更多基本的 Python 技巧。

多重赋值

多重赋值可以同时对多个变量进行赋值,在多次初始化或者交换时很有用。

      """multiple initialization"""
a, b = 1, 2
"""swap"""
a, b = b, a
# a:2, b:1
    

鼓舞人心的例子

      """next assignment in linked list"""
# L206: reverse a linked list
def reverse(head: ListNode) -> ListNode:
    prev, cur = None, head
    while cur:
        cur.next, cur, prev = prev, cur.next, cur
    return prev
    

进一步了解

多重分配是一种打包-解包技术。

      a, b = b, a
    

相当于

      pack = (b, a)
a = pack[0]
b = pack[1]
    

从实现机制上我们可以看出,所谓的“同时”赋值其实是顺序执行的。所以在复杂的场景中,一定要注意赋值的顺序。看下面两个例子。

交换数组元素

错误版本

      """nums[0] has been changed before usage"""
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
    

正确版本

      nums[nums[0]], nums[0] = nums[0], nums[nums[0]]
    

交换链接列表节点

错误版本

      """cur.next has been changed before usage"""
cur.next, cur.next.next.next, cur.next.next = cur.next.next, cur.next, cur.next.next.next
    

正确版本

      cur.next.next.next, cur.next.next, cur.next = cur.next, cur.next.next.next, cur.next.next
    

镜像索引

一些程序员可能会对负索引感到困惑,因为正索引从 0 开始,而负索引从 -1 开始。

如果你对-感到困惑,并且想寻找另一种更易于理解的向后索引方式,你可以尝试镜像索引~ — 向前的镜像。它从最右边的~0开始,更加统一。

正如我在本帖中所说~实际上是一种二进制补码的数学技巧,在某些情况下更容易理解。

      """index start from right to left"""
arr = ["a", "b", "c", "d"]
arr[~0], arr[~1]
# output: ('d', 'c')
    

鼓舞人心的例子

以下是镜像索引~的典型用法

      """swap mirror node"""
def reverse(arr: List[int]) -> None:
    for i in range(len(arr) // 2):
        arr[i], arr[~i] = arr[~i], arr[i]

"""find median in a sort list"""
def median(arr: List[float]) -> float:
    mid = len(arr) // 2
    return (arr[mid] + arr[~mid]) / 2

"""deal with mirror pairs"""
# L246: verify whether a number is strobogrammatic
# strobogrammatic number looks the same when rotated 180 degrees
def is_strobogrammatic(num: str) -> bool:
    return all(num[i] + num[~i] in '696 00 11 88' for i in range(len(num) // 2 + 1))
    

返回 None

Python在任何函数末尾都添加了隐式的return None 。因此,如果函数未指定返回值,则默认返回None 。

说白了,return None就等于return,也等于不返回。

鼓舞人心的例子

      """no return equals to return None, more concise"""
# L226: invert a binary tree
def invert_tree(root: TreeNode) -> TreeNode:
    if root:
        root.left, root.right = invertTree(root.right), invertTree(root.left)
        return root
    

切片分配

当你在=运算符的左侧指定切片时,这意味着切片赋值。切片赋值是列表的一种特殊语法,你可以在一个操作中插入、删除或替换另一个列表中的旧切片:

      arr = [0, 1, 2, 3, 4, 5]

"""insert"""
arr[1:1] = [6, 7]
# arr: [0, 6, 7, 1, 2, 3, 4, 5]

"""delete"""
arr[1:3] = []
# arr: [0, 1, 2, 3, 4, 5]

"""replace"""
arr[1:3] = [6, 7]
# arr: [0, 6, 7, 3, 4, 5]

"""replace slice with different size"""
arr[-2:] = [2] * 3
# arr: [0, 6, 7, 3, 2, 2, 2]

"""replace the entire list"""
arr[:] = [1, 2, 3]
# arr: [1, 2, 3]
    

鼓舞人心的例子

      """replace(or batch assignment) by slice assignment"""
# L280: reorder unsort array in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3]...
def wiggle_sort(nums: List[int]) -> None:
    for i in range(len(nums)):
        nums[i:i+2] = sorted(nums[i:i+2], reverse=i%2)
    

最大/最小整数

如果您需要Java 中类似Integer.MAX_VALUE的东西,那么您可以使用float('inf'),这要归功于 Python 的动态类型。

      """float('inf'), float('-inf') as the initial value of min_val and max_val"""
min_val, max_val = float('inf'), float('-inf')

for i in range(10):
    min_val = min(min_val, i)
    max_val = max(max_val, i)
# min_val:0, max_val:9
    

对于其他/而其他

根据Raymond Hettinger 的《将代码转换为美观、惯用的 Python》 , for else / while else区分了循环中的多个退出点。它是某些GOTO用例的替代品。此处else更准确的术语no break

据我了解,当您同时关心中断非中断逻辑时使用它,并允许您省略跟踪变量。

      found_obj = None
for obj in objects:
    if obj.key == search_key:
        found_obj = obj
        break
else:	# no break
    print('no object found')
    

模拟开关

Python 没有switch关键字,但有几种方法可以模拟switch。简单直观的方法是“if-else-if”阶梯式。但是,由于有跳转表,switch 语句比此解决方案快得多。

更加 Pythonic 的方法是使用带有lambda 的字典映射(关联数组) :

      """emulate switch/case with dict mapping"""
def op_dict(operator: str, x: float, y: float) -> float:
     return {
         '+': lambda: x + y,
         '-': lambda: x - y,
         '*': lambda: x * y,
         '/': lambda: x / y,
     }.get(operator, lambda: None)()

op_dict('*', 2, 3)
# output: 6
    

另一种方法,可以使用反射技术(getattr)来动态确定在运行时需要调用哪个函数。

装饰器

这里很好地解释了Python的装饰器机制:

在 Python 中,函数是第一类对象。这意味着它们支持诸如作为参数传递、从函数返回、修改和分配给变量等操作。

装饰器是 Python 中非常强大且有用的工具,因为它们允许程序员修改函数或类的行为。装饰器允许我们包装另一个函数,以扩展包装函数的行为,而无需永久修改它。

鼓舞人心的例子

在下面的例子中,我们使用装饰器技术来装饰斐波那契函数,然后用记忆化来增强它。

      from functools import wraps
def memoization(func):
    cache = {}
    miss = object()
 
    @wraps(func)
    def wrapper(*args):
        result = cache.get(args, miss)
        if result is miss:
            result = func(*args)
            cache[args] = result
        return result<fon
以上内容来自杭州电子商务研究院推送
分享到:

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

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