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
12
# 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
18
# 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
15
# 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
19
# 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
12
13
# 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
9
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