[摘要]Python 最佳实践指南

文档地址 The Hitchhiker’s Guide to Python!

这份文档

目标对象:入门后,有一定基础的Pythonista
关键词:最佳实践,Pythonic,各类工具介绍

粗粗粗略地过了一遍,大体捞了一些东西出来,大段大段英文太费眼了,回头细读在更新进来

浓缩版,20分钟可大体过完,然后根据自己需要去看详细的吧

整体内容还是很不错的,建议细读英文

PS:文档含有巨量的TODO(没写空白着待补充的),不过但从目录上来看还是很强大滴,相信完善后,会成为一份很牛逼的指南(难度比官方指南高一点点)


第零部分 Getting Started

链接

不解释,不翻译,自个看….真的没啥(每本入门书籍第一章…)


第一部分 Writing Great Code

Structuring Your Project

链接

import 最佳实践

Very bad

[...]
from modu import *
[...]
x = sqrt(4)  # Is sqrt part of modu? A builtin? Defined above?

Better

from modu import sqrt
[...]
x = sqrt(4)  # sqrt may be part of modu, if not redefined in between

Best

import modu
[...]
x = modu.sqrt(4)  # sqrt is visibly part of modu's namespace

Python中关于OOP的 观点

Decorators

def foo():
    # do something

def decorator(func):
    # manipulate func
    return func

foo = decorator(foo)  # Manually decorate

@decorator
def bar():
    # Do something
# bar() is decorated

动态类型(Dynamic typing)

Avoid using the same variable name for different things.

Bad

a = 1
a = 'a string'
def a():
    pass  # Do something

Good

count = 1
msg = 'a string'
def func():
    pass  # Do something

It is better to use different names even for things that are related, when they have a different type:

Bad

items = 'a b c d'  # This is a string...
items = items.split(' ')  # ...becoming a list
items = set(items)  # ...and then a set

可变和不可变类型(Mutable and immutable types)

字符串拼接最佳实践

Bad

# create a concatenated string from 0 to 19 (e.g. "012..1819")
nums = ""
for n in range(20):
  nums += str(n)   # slow and inefficient
print nums

Good

# create a concatenated string from 0 to 19 (e.g. "012..1819")
nums = []
for n in range(20):
  nums.append(str(n))
print "".join(nums)  # much more efficient

Best

# create a concatenated string from 0 to 19 (e.g. "012..1819")
nums = [str(n) for n in range(20)]
print "".join(nums)

join() is not always best 创建新字符串和修改原有字符串

foo = 'foo'
bar = 'bar'

foobar = foo + bar  # This is good
foo += 'ooo'  # This is bad, instead you should do:
foo = ''.join([foo, 'ooo'])

字符串格式化

foo = 'foo'
bar = 'bar'

foobar = '%s%s' % (foo, bar) # It is OK
foobar = '{0}{1}'.format(foo, bar) # It is better
foobar = '{foo}{bar}'.format(foo=foo, bar=bar) # It is best

Code Style

链接

一般概念(General concepts)

明确的代码

Bad

def make_complex(*args):
    x, y = args
    return dict(**locals())

Good

def make_complex(x, y):
    return {'x': x, 'y': y}

每行一个声明

Bad

print 'one'; print 'two'

if x == 1: print 'one'

if <complex comparison> and <other complex comparison>:
    # do something

Good

print 'one'
print 'two'

if x == 1:
    print 'one'

cond1 = <complex comparison>
cond2 = <other complex comparison>
if cond1 and cond2:
    # do something

函数参数

#不解释了
位置参数,默认参数,*args, **args

Avoid the magical wand(这个肿么翻…)

原因:
Python comes with a very rich set of hooks and tools allowing to do almost any kind of tricky tricks

建议:
it is always better to use the most straightforward way to achieve your goal

感受一下:
We consider that a Python developer should know about these nearly infinite possibilities,
because it grows the confidence that no hard-wall will be on the way.
However, knowing how to use them and particularly when not to use them is the most important.

Like a Kungfu master, a Pythonista knows how to kill with a single finger, and never to actually do it.

其实就是告诉你,骚年,这玩意你要去学习去了解去掌握,目的是增强实力保持自信,但是不要去用啊
(说的原子弹吧....)

方言(Idioms)

Idiomatic Python code is often referred to as being Pythonic.

列举了一些:

Unpacking

for index, item in enumerate(some_list):
    # do something with index and item

a, b = b, a

a, (b, c) = 1, (2, 3)

忽略接收变量,这里用的是两个下划线,原因 http://docs.python-guide.org/en/latest/writing/style/#create-an-ignored-variable

filename = 'foobar.txt'
basename, __, ext = filename.rpartition('.')

同一个元素创建一个长度为N的列表

four_nones = [None] * 4

创建一个长度N的嵌套列表

four_lists = [[] for __ in xrange(4)]

由列表拼接字符串

letters = ['s', 'p', 'a', 'm']
word = ''.join(letters)

快速查找

d = {'s': [], 'p': [], 'a': [], 'm': []}
l = ['s', 'p', 'a', 'm']

def lookup_dict(d): #O(1)
    return 's' in d

def lookup_list(l): #O(n)
    return 's' in l

Zen of Python

import this

PEP8

$ pip install pep8
$ pep8 optparse.py
optparse.py:69:11: E401 multiple imports on one line
optparse.py:77:1: E302 expected 2 blank lines, found 1

惯例(Conventions)

判断值是否等于常量

Bad:

if attr == True:
    print 'True!'

if attr == None:
    print 'attr is None!'

Good:

# Just check the value
if attr:
    print 'attr is truthy!'

# or check for the opposite
if not attr:
    print 'attr is falsey!'

# or, since None is considered false, explicitly check for it
if attr is None:
    print 'attr is None!'

获取字典元素

Bad:

d = {'hello': 'world'}
if d.has_key('hello'):
    print d['hello']    # prints 'world'
else:
    print 'default_value'

Good:

d = {'hello': 'world'}

print d.get('hello', 'default_value') # prints 'world'
print d.get('thingy', 'default_value') # prints 'default_value'

# Or:
if 'hello' in d:
    print d['hello']

快捷列表操作

Bad:

# Filter elements greater than 4
a = [3, 4, 5]
b = []
for i in a:
    if i > 4:
        b.append(i)

Good:

a = [3, 4, 5]
b = [i for i in a if i > 4]
b = filter(lambda x: x > 4, a)

Bad:

# Add three to all list members.
a = [3, 4, 5]
for i in range(len(a)):
    a[i] += 3

Good:

a = [3, 4, 5]
a = [i + 3 for i in a]
# Or:
a = map(lambda i: i + 3, a)

使用enumerate

for i, item in enumerate(a):
    print i, item
# prints
# 0 3
# 1 4
# 2 5

读文件

Bad:

f = open('file.txt')
a = f.read()
print a
f.close()

Good:

with open('file.txt') as f:
    for line in f:
        print line

超长的行

Bad:

my_very_big_string = """For a long time I used to go to bed early. Sometimes, \
    when I had put out my candle, my eyes would close so quickly that I had not even \
    time to say “I’m going to sleep.”"""

from some.deep.module.inside.a.module import a_nice_function, another_nice_function, \
    yet_another_nice_function

Good:

#受教了....
my_very_big_string = (
    "For a long time I used to go to bed early. Sometimes, "
    "when I had put out my candle, my eyes would close so quickly "
    "that I had not even time to say “I’m going to sleep.”"
)

from some.deep.module.inside.a.module import (
    a_nice_function, another_nice_function, yet_another_nice_function)

Reading Great Code

链接

感受下:The number one thing that Python programmers do is read code.

再感受一把:One of the secrets of becoming a great Python programmer is to read, understand, and comprehend excellent code.

几个推荐阅读源代码项目

Howdoi

Flask

Werkzeug

Requests

Tablib

文档(Documentation)

链接

感受一下:Readability is a primary focus for Python developers, in both project and code documentation.

具体还是读原文吧

项目文档组成

1.A README file
  at the root directory should give general information to the users and the maintainers.

  reStructuredText 或 Markdown
2.An INSTALL file
  is less necessary with python

  setup.py

3.A LICENSE file
  should always be present and specify the license under which the software is made available to the public
4.A TODO file or a TODO section in README
  should list the planned development for the code.
5.A CHANGELOG file or section in README
  should compile a short overview of the changes in the code base for the latest versions.

几种文档工具

Sphinx(听说最强大....)
reStructuredText
Markdown(俺的最爱...)

代码文档建议

Comments clarify code and begin with a hash (#).

In Python, docstrings describe modules, classes, and functions:

def square_and_rooter(x):
    """Returns the square root of self times self."""

注解代码块

Do not use triple-quote strings to comment code.

This is not a good practice, because line-oriented command-line tools such as grep will not be aware that the commented code is inactive.

It is better to add hashes at the proper indentation level for every commented line.

最佳实践:

不用三引号注解代码块
每一行加#来注释

测试你的代码(Testing Your Code)

链接

测试一些通用原则

1.A testing unit should focus on one tiny bit of functionality and prove it correct.
2.Each test unit must be fully independent
3.Try hard to make tests that run fast
4.Learn your tools and learn how to run a single test or a test case
5.Always run the full test suite before a coding session, and run it again after.
6.It is a good idea to implement a hook that runs all tests before pushing code to a shared repository.
7.If you are in the middle of a development session and have to interrupt your work,
  it is a good idea to write a broken unit test about what you want to develop next.
8.The first step when you are debugging your code is to write a new test pinpointing the bug.
9.Use long and descriptive names for testing functions
10.When something goes wrong or has to be changed, and if your code has a good set of tests,
  you or other maintainers will rely largely on the testing suite to fix the problem or modify a given behavior.
11.Another use of the testing code is as an introduction to new developers.

单元测试(Unittest)

Python内置模块, 文档

import unittest

def fun(x):
    return x + 1

class MyTest(unittest.TestCase):
    def test(self):
        self.assertEqual(fun(3), 4)

文档测试(Doctest)

非精细case,只验证主体功能可用

def square(x):
    """Squares x.

    >>> square(2)
    4
    >>> square(-2)
    4
    """

    return x * x

if __name__ == '__main__':
    import doctest
    doctest.testmod()

相关工具

py.text $ pip install pytest

Nose unittest的扩展 $ pip install nose

tox $ pip install tox

Unittest2 $ pip install unittest2

mock $ pip install mock

Common Gotchas(不懂怎么翻…╮(╯▽╰)╭ )

一些新手可能疑惑的例子

两个例子

1.可变默认参数

What You Wrote

def append_to(element, to=[]):
    to.append(element)
    return to

What You Might Have Expected to Happen

my_list = append_to(12)
print my_list

my_other_list = append_to(42)
print my_other_list

[12]
[42]

What Does Happen

[12]
[12, 42]

What You Should Do Instead

def append_to(element, to=None):
    if to is None:
        to = []
    to.append(element)
    return to

Python默认参数在函数定义处执行一次,而不是每次函数调用时执行。

2.Late Binding Closures(又一个,延迟绑定闭包?)

What You Wrote

def create_multipliers():
    return [lambda x : i * x for i in range(5)] #

What You Might Have Expected to Happen

for multiplier in create_multipliers():
    print multiplier(2) # 任意一个返回的函数被调用时,内部循环i=4

0
2
4
6
8

What Does Happen

8
8
8
8
8

What You Should Do Instead

from functools import partial
from operator import mul

def create_multipliers():
    return [partial(mul, i) for i in range(5)]

Python的闭包是延时绑定

选择证书(Choosing a License)

链接

开源证书 列表

证书选择器 入口


第二部分 Scenario Guide

都是介绍性质的,类似工具目录,而且大部分是空的,目前没详细信息

要了解具体,goole相关关键词吧

具体自己翻吧 位置

目录:

Network Applications

Http:

Requests

Distributed Systems

ZeroMQ
RabbitMQ

Web Applications

Context

WSGI

Frameworks

Django
Flask
Werkzeug
Tornado
Pyramid

Web Servers

Nginx

WSGI Servers

Gunicorn

Hosting

PasS (Platform as a service)
Heroku
DotCloud
Gondor

Templating

Jinja2

HTML Scraping

lxml
Requests

Command Line Applications

Clint
docopt

GUI Applications

Qt
Cocoa
wxPython
GTk
Tk
Kivy
PyjamasDesktop (pyjs Desktop)
Camelot

Databases

DB-API
SQLAlchemy
Django ORM

Networking

Twisted
PyZMQ
gevent

Systems Administration

Fabric
Salt
Psutil
Chef
Puppet
Blueprint
Buildout

Continuous Integration

Jenkins
Buildbot
Mule?
Tox
Travis-CI

Speed

C Extensions

GIL
Cython
Pyrex
Shedskin
Numba

Threading

Threading
Multiprocessing

###Scientific Applications

Tools

IPython

Libraries

NumPy
Numba
SciPy
Matplotlib
Pandas
Rpy2
PsychoPy

Image Manipulation

Python Imaging Library(PIL)

XML parsing

untangle
xmltodict

有需要自取…..

第三部分 Shipping Great Code

http://docs.python-guide.org/en/latest/#shipping-great-code

第四部分 Development Environment

http://docs.python-guide.org/en/latest/#development-environment

第五部分 Additional Notes

http://docs.python-guide.org/en/latest/#additional-notes


The end!

2013-11-25

wklken


python

2846 Words

2013-11-25 00:00 +0000