Python进阶

在熟悉了python的基本语法后,通过不断地实践,越发地爱上了这门语言。需要深入地理解和用好它。

在学习PEP 8相关文档过程中,获得了一份很好的文档,里面介绍了几个tips,值得python新手进阶的时候学习。

What’s an Idiom

Idioms我觉得在这里叫惯用语最合适,指的是使用python的过程中符合python哲学的“正确”做法。通俗一点可以叫套路,高雅一点可以叫范式。相比错误的做法,采用这些idioms,有以下好处。

  1. 可读性高
  2. 执行效率高
  3. 内存占用少

让程序可执行亦可引入

代码如下:

1
if __name__ == '__main__':

这句代码让该脚本能够在cmd中python xxx.py执行,也可以作为一个 module 被别的代码进行import。

正确地判断布尔值

代码如下:

1
2
if x:
if not x:

不要像C语言那样各种判断,python的数据类型都进行了封装。例如:

1
2
3
4
5
6
7
8
9
10
# GOOD
name = 'Safe'
pets = ['Dog', 'Cat', 'Hamster']
owners = {'Safe': 'Cat', 'George': 'Dog'}
if name and pets and owers:
print("we have pets")

# NOT SO GOOD
if name != '' and len(pets) > 0 and owers != {}:
print("we have pets")

不必在判断非空这件事情上浪费代码。

使用 in

代码如下:

1
2
3
4
# container
if item in items:
# iteration
for item in items:

分别举例说明一下。

a. 容器

1
2
3
4
5
6
7
8
# GOOD
name = 'Safe Hammad'
if 'H' in name:
print("ok")

# NOT SO GOOD
if name.find('H')! = -1:
print("ok")

这样的写法,阅读很清晰。能够在内置的数据类型中使用(包括列表,字典,集合,字符串)。封装的类,如果实现了contains 方法,也可以实现。

b. 迭代器

1
2
3
4
5
6
7
8
9
10
# GOOD
pets = ['Dog', 'Cat', 'Hamster']
for pet in pets
print(pet)

# NOT SO GOOD
i = 0
while i < len(pets):
print('A', pets[i], 'can be very cute!')
i += 1

这样的写法,代码更加简洁。同样在内置的数据类型中使用。封装的类,如果实现了iter 方法,也可以实现。这极大地简化了for循环的语句。

交换变量

代码如下:

1
a, b = b, a

不必再像C语言使用temp变量进行交换,减少代码。

使用序列生成字符串

代码如下:

1
''.join(some_strings)

相比使用+拼接字符串,时间复杂度更低。

1
2
3
4
5
6
7
8
9
10
11
# GOOD
chars = ['S', 'a', 'f', 'e']
name = ''.join(chars)
print(name)

# NOT SO GOOD
chars = ['S', 'a', 'f', 'e']
name = ''
for char in chars:
name += char
print(name)

捕获异常

代码如下:

1
2
try:
except:

这里有个概念,鸭子类型(duck typing)。它指的是,如果一个对象,走路像鸭子,叫声像鸭子,那么它一定是鸭子。这是面向对象中的多态(polymorphism)的理论。使用异常而不是使用if来进行各种判断检查,将把我们通过写代码排除各种特殊情况中解放出来。
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
# GOOD
d = {'x': '5'}
try:
value = int(d['x'])
except (KeyError, TypeError, ValueError):
value = None
# NOT SO GOOD
if 'x' in d and \
isinstance(d['x'], str) and \
d['x'].isdigit():
value = int(d['x'])
else:
value = None

枚举

代码如下:

1
for i, item in enumerate(items):

当既需要遍历容器内的元素,又需要容器内元素的下标时,这个方法便派上用场了。

表达式来构建列表

代码如下:

1
[i * 3 for i in data if i > 10]

对于一些比较简单的变换,这种方法非常简洁。如果太复杂,还是使用常规的for+if的语句。我认为判断的依据在于该语句是否太长而影响可读性。

zip创建字典

代码如下

1
d = dict(zip(keys, values))

代码简洁,避免使用循环进行创建。

使用 _ 接收无用变量

代码如下:

1
for k, _ in [('a', 1), ('b', 2), ('c', 3)]

对于元组中的数值我们不需要,那么使用下划线来接收。如果是以下形式:

1
for k, j in [('a', 1), ('b', 2), ('c', 3)]

难免阅读者会去考虑变量j的用途,影响可读性。

总结

这些idioms很有帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
if __name__ == '__main__':

if x:
if not x:

# container
if item in items:
# iteration
for item in items:

a, b = b, a

for k, _ in [('a', 1), ('b', 2), ('c', 3)]

这些我现在已经深刻理解,成为我的python代码风格一部分,

1
2
3
4
5
6
7
8
9
10
''.join(some_strings)

try:
except:

d = dict(zip(keys, values))

for i, item in enumerate(items):

[i * 3 for i in data if i > 10]

这些我还需要继续熟悉之中。

参考

  1. http://safehammad.com/downloads/python-idioms-2014-01-16.pdf
  2. https://docs.python.org/3.1/howto/doanddont.html