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
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~