客至汲泉烹茶, 抚琴听者知音

【译】你应该知道的20个python小技巧

原文地址,并删除了部分太简单的内容,添加了我认为有用的一些技巧。

本文介绍了20种可能有用的python小技巧。

1.Python之禅(The Zen of Python)

Python之禅(也称为PEP 20)是Tim Peters撰写的一小段文字,代表设计和使用Python的指导原则。可以在Python网站上找到它,但是也可以在控制台中输入以下代码获得:

>>> import this 
'''
Beautiful is better than ugly.#优美胜于丑陋。
Explicit is better than implicit.#显式胜于隐式。
Simple is better than complex. # 简单胜于复杂。
Complex is better than complicated.#复杂胜于难懂。
Flat is better than nested.#扁平胜于嵌套。
Sparse is better than dense.#间隔胜于紧凑(代码应该有适当的间隔)。
Readability counts.#可读性应当被重视。
Special cases aren’t special enough to break the rules. Although practicality beats purity.
#尽管实用性会打败纯粹性,特例也不能凌驾于规则之上。
Errors should never pass silently. Unless explicitly silenced.
#不要包容所有错误,除非你需要这样做
In the face of ambiguity, refuse the temptation to guess.#面对不确定性,拒绝猜测。
There should be one– and preferably only one –obvious way to do it.
#尽量找一种,最好是唯一一种明显的解决方案
Although that way way not be obvious at first unless you’re Dutch.
#虽然一开始这种方法并不是显而易见的,但谁叫你不是Python之父呢。
Now is better than never. Although never is often better than right now.
#做比不做好,但立马去做有时还不如不做。
If the implementation is hard to explain, it’s a bad idea.
#如果方案很难说明,那它是个坏想法。
If the implementation is easy to explain, it may be a good idea
#如果方案容易解释,那它有可能是个好想法。
Namespaces are one honking great idea – let’s do more of those!
#命名空间是个绝妙的想法,让我们多多地使用它们吧!
'''

2.链式赋值(Chained Assignment)

如果需要多个变量来引用同一对象,则可以使用链式赋值:

>>> x = y = z = 2
>>> x, y, z
(2, 2, 2)

逻辑优雅,对吗?

这种方法被称为序列解包(tuple unpacking),你也可以在一条语句中为多个变量赋值:

>>> x, y, z = 2, 4, 8
>>> x
2
>>> y
4
>>> z
8

请注意,第一个语句中的2,4,8是一个等价于(2,4,8)的元组。

3.更高级的多重赋值(More Advanced Multiple Assignment)

在普通的多重赋值之外,python还有更强大的赋值方法,您不需要在左右两侧使用相同数量的元素:

>>> x, *y, z = 2, 4, 8, 16
>>> x
2
>>> y
[4, 8]
>>> z
16

在这种情况下,x取第一个值(2),因为它排在第一位。 z是最后一个,取最后一个值(8)。 y变成列表,包含其他所有元素,因为它带有星号(* y)

4.链式对比(Chained Comparison)

您可以通过将多个比较运算符合并到一个Python表达式中。如果所有比较正确,则此表达式返回True,否则返回False:

>>> x = 5
>>> 2 < x ≤ 8
True
>>> 6 < x ≤ 8
False

它类似于(2 <x)和(x≤8)和(6 <x)和(x≤8),但更简洁,并且只需要对x求一次值即可。

下面的代码也是合法的:

>>> 2 < x > 4
True

你甚至可以写更多的比较:

>>> x = 2
>>> y = 8
>>> 0 < x < 4 < y < 16
True

5.链式函数调用

你可以在一行代码内调用多个函数。

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

a, b = 4, 5
print((subtract if a > b else add)(a, b)) # 9 

6.交换变量(Swap Variables)

您可以以简洁的方式直接交换变量,而无需引入第三个变量。

>>> x, y = 2, 8
>>> x
2
>>> y
8
>>> x, y = y, x
>>> x
8
>>> y 
2

7.合并字典(Merge Dictionaries)

合并两个或多个词典的一种方法是在新的字典中将它们解包:

>>> x = {'u': 1}
>>> y = {'v': 2}
>>> z = {**x, **y, 'w': 4}
>>> z
{'u': 1, 'v': 2, 'w': 4}

8.列表展开

def spread(arg):
    ret = []
    for i in arg:
        if isinstance(i, list):
            ret.extend(i)
        else:
            ret.append(i)
    return ret

def deep_flatten(lst):
    result = []
    result.extend(
        spread(list(map(lambda x: deep_flatten(x) if type(x) == list else x, lst))))
    return result

deep_flatten([1, [2], [[3], 4], 5]) # [1,2,3,4,5]

9.高级迭代(Advance Iteration)

如果要遍历序列,并且需要序列元素和相应的索引,则应使用enumerate:

>>> for i, item in enumerate(['u', 'v', 'w']):
... print('index:', i, 'element:', item)
... 
index: 0 element: u
index: 1 element: v
index: 2 element: w

在每次迭代中,您都将获得一个带有索引和相应元素的元组。

10.反向迭代(Reversed Iteration)

如果要以相反的顺序遍历序列,则应使用reversed:

>>> for item in reversed(['u', 'v', 'w']):
... print(item)
... 
w
v
u

11.聚和元素(Aggregate Elements)

如果要汇总多个序列中的元素,则应使用zip:

>>> x = [1, 2, 4]
>>> y = ('u', 'v', 'w')
>>> z = zip(x, y)
>>> z

>>> list(z)
[(1, 'u'), (2, 'v'), (4, 'w')]

您可以遍历zip对象或将其转换为列表或元组。

12.转置矩阵(Transpose Matrices)

尽管人们在处理矩阵时通常会使用NumPy(或类似的库),但是您也可以使用zip获得矩阵的转置:

>>> x = [(1, 2, 4), ('u', 'v', 'w')]
>>> y = zip(*x)
>>> z = list(y)
>>> z
[(1, 'u'), (2, 'v'), (4, 'w')]

13.唯一值(Unique Values)

如果元素的顺序不重要,则可以通过将其转换为集合来删除列表中的重复项:

>>> x = [1, 2, 1, 4, 8]
>>> y = set(x)
>>> y
{8, 1, 2, 4}
>>> z = list(y)
>>> z
[8, 1, 2, 4]

14.序列排序(Sort Sequences)

默认情况下,序列按其首个元素排序:

>>> x = (1, 'v')
>>> y = (4, 'u')
>>> z = (2, 'w')
>>> sorted([x, y, z])
[(1, 'v'), (2, 'w'), (4, 'u')]

如果要根据它们的第二个(或其他)元素对它们进行排序,则可以使用参数key和适当的lambda函数作为相应的参数:

>>> sorted([x, y, z], key=lambda item: item[1])
[(4, 'u'), (1, 'v'), (2, 'w')]

类似地,你也可以进行反向排序:

>>> sorted([x, y, z], key=lambda item: item[1], reverse=True)
[(2, 'w'), (1, 'v'), (4, 'u')]

15.字典排序(Sort Dictionaries)

您可以使用和上面类似的方法,对通过.items()方法获得的字典的键值元组进行排序:

>>> x = {'u': 4, 'w': 2, 'v': 1}
>>> sorted(x.items())
[('u', 4), ('v', 1), ('w', 2)]

如果想根据值对它们进行排序,则应该指定key的值为item[1](因为item[0]是键),也可以反向排序

>>> sorted(x.items(), key=lambda item: item[1])
[('v', 1), ('w', 2), ('u', 4)]
>>> sorted(x.items(), key=lambda item: item[1], reverse=True)
[('u', 4), ('w', 2), ('v', 1)]

16.原始的格式化字符串(Raw Formatted Strings)

Python 3.6引入了所谓的格式化字符串( formatted strings,f-strings)。您可以将表达式嵌入此类字符串中,它可以同时输出原始字符串和格式化的字符串。您需要同时包含两个前缀:fr。

>>> fr'u \ n v w={2 + 8}'
'u \\ n v w=10'

17.检查两个字符串的组成元素是不是一样的

from collections import Counter

def anagram(first, second):
    return Counter(first) == Counter(second)

18.获得最大(或最小)元素的索引(Obtain the Index of the Maximal (or Minimal) Element)

Python没有提供直接获取列表或元组中最大或最小元素索引的方法。幸运的是,有(至少)两种优雅的方式可以做到这一点:

>>> x = [2, 1, 4, 16, 8]
>>> max((item, i) for i, item in enumerate(x))[1]
3

如果存在两个或多个具有最大值的元素,则此方法返回最后一个元素的索引:

>>> y = [2, 1, 4, 8, 8]
>>> max((item, i) for i, item in enumerate(y))[1]
4

要获取第一次出现的索引,您需要稍微更改前一段代码:

>>> -max((item, -i) for i, item in enumerate(y))[1]
3

另一种方法可能更优雅:

>>> x = [2, 1, 4, 16, 8]
>>> max(range(len(x)), key=lambda i: x[i])
3
>>> y = [2, 1, 4, 8, 8]
>>> max(range(len(y)), key=lambda i: x[i])
3

要查找最小元素的索引,请使用函数min。

19.获得笛卡尔乘积(Obtain the Cartesian Product)

内置模块itertools提供了许多有用的类。其中之一用于获得笛卡尔乘积:

>>> import itertools
>>> x, y, z = (2, 8), ['u', 'v', 'w'], {True, False}
>>> list(itertools.product(x, y, z))
[(2, 'u', False), (2, 'u', True), (2, 'v', False), (2, 'v', True),
(2, 'w', False), (2, 'w', True), (8, 'u', False), (8, 'u', True),
(8, 'v', False), (8, 'v', True), (8, 'w', False), (8, 'w', True)]

20.矩阵乘法运算符(The Operator for Matrix Multiplication)

Python 3.5引入了专用的矩阵乘法运算符@,它简单优雅:

>>> import numpy as np
>>> x, y = np.array([1, 3, 5]), np.array([2, 4, 6])
>>> z = x @ y
>>> z
44
这一点是我尤其想要推荐的,受到之前知识的影响,我一直以为用@的就是装饰器,但其实不是的。python中用@的还有矩阵乘法!我说之前看机器学习代码的时候,有个@怎么也看不懂,原来是我理解错了。

添加新评论