前言
在本文中,我将向您展示Python中很常见的5个特性。有经验的Python开发人员可能认识其中一些。然而,这对其他人仍将是未知的。
1...
是的,你没看错,在Python中...是一个有效的构造。...是称为省略号的单例对象。如果你把它输入到Python解释器中,你可以看到它:
- >>> ...
- Ellipsis
根据官方文档,省略号是“一种特殊值,主要与用户定义容器数据类型的扩展切片语法结合使用”。它有两个主要的用例。一种是在空函数中充当占位符体。另一个是Numpy,作为一个切片项,就像文档中描述的那样。
函数的占位符
- def my_awesome_function():
- ...
这相当于:
- def my_awesome_function():
- Ellipsis
还有这个:
- def my_awesome_function():
- pass
注意,我不是说pass =…我只是说作为函数体,结果是一样的。事实上,您可以使用任何东西作为占位符。
Numpy
下面的代码基本上意味着创建一个矩阵数组。每个矩阵是3×3。然后获取所有最内部矩阵的第二列(numpy数组基于0)。
- import numpy as np
- >>> array = np.arange(27).reshape(3, 3, 3)
- >>> array
- array([[[ 0, 1, 2],
- [ 3, 4, 5],
- [ 6, 7, 8]],
- [[ 9, 10, 11],
- [12, 13, 14],
- [15, 16, 17]],
- [[18, 19, 20],
- [21, 22, 23],
- [24, 25, 26]]])
- >>> array[..., 1]
- array([[ 1, 4, 7],
- [10, 13, 16],
- [19, 22, 25]])
- >>> # This is equivalent to
- >>> array[:, :, 1]
- array([[ 1, 4, 7],
- [10, 13, 16],
- [19, 22, 25]])
2一个优雅的解包
可迭代解包是一种非常方便的特性,已经存在一段时间了。大多数人使用它来解包包含多个项的可迭代对象。例如,考虑以下用例。
- >>> a, *b, c = range(1, 11)
- >>> a
- 1
- >>> c
- 10
- >>> b
- [2, 3, 4, 5, 6, 7, 8, 9]
或者是:
- >>> a, b, c = range(3)
- >>> a
- 0
- >>> b
- 1
- >>> c
- 2
但有一个很好的用例,很多人都没有利用它,那就是拆封单个迭代器。为什么这很有用?恕我直言,它使代码更优雅了一些。
而不是这样做:
- >>> lst = [1]
- >>> a = lst[0]
- >>> a
- 1
- >>> (a, ) = lst
- >>> a
- 1
你可以这样做:
- >>> lst = [1]
- >>> [a] = lst
- >>> a
- 1
我知道这可能看起来很傻,但至少对我来说,它看起来更优雅。
3你能让这个列表躺平吗?
扁平化列表有几种方法。最简单的是使用列表理解。
- >>> l = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
- >>> flattened = [elem for sublist in l for elem in sublist]
- >>> flattened
- [1, 2, 3, 4, 5, 6, 7, 8, 9]
如果您更倾向于函数式编程,您可以使用减速器。
- >>> from functools import reduce
- >>> reduce(lambda x,y: x+y,l)
- [1, 2, 3, 4, 5, 6, 7, 8, 9]
然而,还有另一种方法。你可以用sum函数!
- >>> sum(l, [])
- [1, 2, 3, 4, 5, 6, 7, 8, 9]
这是因为sum函数遍历列表中的每个元素,并将它们与作为第二个参数传递的默认值连接起来。因为Python中的列表可以用+操作符连接,所以你得到的结果是这样的:
- >>> sum(l, []) ==> [] + [1, 2, 3] + [4, 5, 6] + [7, 8, 9]
- [1, 2, 3, 4, 5, 6, 7, 8, 9]
尽管这个技巧很高明,但它绝不是可读的。而且,它的性能也很糟糕。
4else
else语句可以用于几个目的。很少有人知道,但是你可以在经典的“if else”块之外使用它。Python允许它用于循环和异常块。
循环
Python有两个不同的循环,for和while。两者都可能是“坏的”。也就是说,如果满足了某个条件,就可以跳出循环。例如:
- In [7]: while a < 10:
- ...: if a == 3:
- ...: print("a == 3. exiting loop.")
- ...: break
- ...: a += 1
- ...:
- a == 3. exiting loop.
现在,假设我们要找一个特定的条件。如果满足该条件,则将结果保存在一个名为found的标志中。然后,如果我们没有找到它,我们打印一条消息。
- found = False
- a = 0
- while a < 10:
- if a == 12:
- found = True
- a += 1
- if not found:
- print("a was never found")
因为a永远不会变成12,所以程序输出a永远不会找到。
好,但是我们在这里怎么用else呢?
else可以用来替换标志。基本上,我们实际需要的是运行循环,如果没有找到,则打印一条消息。
- a = 0
- while a < 10:
- if a == 12:
- break
- a += 1
- else:
- print("a was never found")
由于它适用于任何循环,所以您可以使用for而不是while。
- for a in range(10):
- if a == 12:
- break
- a += 1
- else:
- print("a was never found")
异常
Python中的else是如此通用,你甚至可以使用try…except。这里的思想是捕获异常不发生的情况。
- In [13]: try:
- ...: {}['lala']
- ...: except KeyError:
- ...: print("Key is missing")
- ...: else:
- ...: print("Else here")
- ...:
- Key is missing
在这个例子中,我们尝试在一个空字典中查找名为“lala”的键。由于“lala”不存在,代码将引发一个KeyError异常。当我在IPython中运行这段代码时,得到了预期的结果。
如果程序没有引发异常呢?
- In [14]: try:
- ...: {'lala': 'bla'}['lala']
- ...: except KeyError:
- ...: print("Key is missing")
- ...: else:
- ...: print("Else here")
- ...:
- Else here
现在我们可以看到它的实际应用。{' lala ': ' bla '}[' lala ']块不会引发KeyError,所以else就起作用了。
5比较
这是我最喜欢的一个,老实说,没有那么隐蔽。与许多编程语言(如Java、C或c++)不同,Python允许链式比较运算符。假设你有一个变量x,它的值是10。现在,假设你想断言x在一个范围内,比如5..20。你可以这样做:
- In [16]: x = 10
- In [17]: if x >= 5 and x <= 20:
- ...: print("x is within range")
- ...: else:
- ...: print("x is outside range")
- ...:
- is within range
事实证明,这可以通过将运算符链接起来来简化。所以,我们可以重构代码为:
- In [18]: if 5 <= x <= 20:
- ...: print("is within range")
- ...: else:
- ...: print("x is outside range")
- ...:
- is within range
这段代码实现了完全相同的结果,但它更加优雅。您可以使用任何一种比较运算符进行链。
- >>> x = 10
- >>> 20 == x > 1
- False
- >>> 25 > x <= 15
- True
- >>> x < 20 < x*10 < 1000
- True