Python Anti-Patterns总结

Readability可读性

1.Asking for permission instead of forgiveness

EAFP (easier to ask for forgiveness than permission)
假设需要的变量/文件文件, 如果有问题则捕获异常

1
2
3
4
5
6
7
8
9
10
11
# Bad
import os
if os.path.exists("file.txt"):
os.unlink("file.txt")
# Great
import os
try:
os.unlink("file.txt")
# raised when file does not exist
except OSError:
pass

2.Not using dict keys when formatting strings

1
2
3
4
5
6
7
8
9
10
11
12
13
# Bad
person = {
'first': 'Tobin',
'age':20
}
print('{0} is {1} years old'.format(person['first'], person['age']))

# Great
person = {
'first': 'Tobin',
'age':20
}
print('{first} is {age} years old'.format(**person))

3.Not using named tuples when returning more than one value from a function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Bad
def get_name():
return "Richard", "Xavier", "Jones"

name = get_name()
# no idea what these indexes map to!
print(name[0], name[1], name[2])

# Great
from collections import namedtuple
def get_name():
name = namedtuple("name", ["first", "middle", "last"])
return name("Richard", "Xavier", "Jones")

name = get_name()
# much easier to read
print(name.first, name.middle, name.last)

4.Not using zip() to iterate over a pair of lists

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Bad
numbers = [1, 2, 3]
letters = ["A", "B", "C"]

for index in range(len(numbers)):
print(numbers[index], letters[index])


# Great
numbers = [1, 2, 3]
letters = ["A", "B", "C"]

for numbers_value, letters_value in zip(numbers, letters):
print(numbers_value, letters_value)

Performance 性能

1.Using key in list to check if key is contained in list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Bad 每次都需要迭代list然后比较, 复杂率 O(n)
l = [1, 2, 3, 4]
# iterates over three elements in the list
if 3 in l:
print("The number 3 is in the list.")
else:
print("The number 3 is NOT in the list.")

# Great set做了去重, 复杂率O(logn)
# Use a set or dictionary instead of a list

# 单次查询效率 set > dict > list

s = set([1, 2, 3, 4])
if 3 in l:
print("The number 3 is in the list.")
else:
print("The number 3 is NOT in the list.")

2.Not using iteritems() to iterate over a large dictionary

只适用于Py2.X, Py3中items默认返回迭代器,iteritems()已经从Py3.x移除

1
2
3
4
5
6
7
8
9
10
11
# Bad
d = {i: i * 2 for i in xrange(10000000)}
# Slow and memory hungry.
for key, value in d.items():
print("{0} = {1}".format(key, value))

# Great
d = {i: i * 2 for i in xrange(10000000)}
# Memory efficient.
for key, value in d.iteritems():
print("{0} = {1}".format(key, value))

database queries

1
2
3
4
5
6
7
8
""" views.py """
from models import Cars

# ...

cars = Cars.objects.all()
for car in cars:
do_something(car.make)

实际对应执行SQL为

SELECT make, model, wheels, ... FROM vehicles_cars;

如果只需要单取make字段, 数据表数据过大或者单个表字段过多, 则会造成没必要的性能消耗.

优化1

1
2
3
4
5
6
7
8
from cars.models import Cars

cars = Cars.objects.all().values('make')

# Print all makes
# 返回字典
for car in cars:
do_something(car['make'])

优化2,返回tuple

1
2
3
4
5
6
7
from cars.models import Cars
cars = Cars.objects.all().values_list('make', flat=True)

# Print all makes
# 返回元组
for make in cars:
do_something(make)

对应的sql

SELECT make from vehicles_cars;

参考: The Little Book of Python Anti-Patterns — Python Anti-Patterns documentation

坚持原创技术分享,您的支持将鼓励我继续创作!