# PYTHON编程习惯

Ξ魂牵梦萦Ξ
1年前 阅读 97 点赞 3

### Python之禅(一) The Zen of Python (1)

There are the guiding principles of Python, but are open to interpretation.

A sense of humor is required to their proper interpretation.

If you are using a programming language named after a sketch comedy troupe, you had better have a sense of humor.

• Beautiful is better than ugly.
• 美丽胜于丑陋
• Explicit is better than implicit.
• 显式胜过隐式
• Simple is better than complex.
• 简单优于复杂
• Complex is better than complicated.
• 复杂好于超复杂
• Flat is better than nested.
• 单一胜过于嵌套
• Sparse is better than dense.
• 稀疏优于稠密
• 可读性很重要
• Special cases aren’t special enough to break the rules.
• 特殊的情况并不足以特殊到打破规则
• Although practicality beats purity.
• 尽管实用性打击代码的纯洁
• Errors should never pass silently.
• 错误绝不应该被默默地放过
• Unless explicitly silenced.
• 除非你有意为之

### Python之禅(二) The Zen of Python (2)

In the face of ambiguity, refuse the temptation to guess.

There should be one – and preferably only one – obvious way to do it.

Although that way may not be obvious at first unless you’re Dutch

Now is better than never.

Although never is often better than right now.

If the implementation is hard to explain, it is a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea – let’s do more of those!

This particular “poem” began as a kind of a joke,
but it really embeds a lot of truth about the philosophy behind python.
The Zen of Python has been formalized in PEP 20, where the abstract reads:
Long time Pythoneer Tim Peters succinctly channels the BDFL’s guding principles for Python’s
design into 20 aphorisms, only 19 of which have been written down.

### 编码规范：可读性很重要 Coding Style: Readability Counts

Program must be writtern for people to read, and only incidentally for machines to exceute.

### PEP 8: Python编码规范指导 PEP 8: Style Guide for Python Code

PEP = Python Enhancement Proposal

PEP = Python提高建议

A PEP is a design document providing information to the Python community,

PEP是一份为Python社区提供的设计文档

or describing a new feature for Python or its processes or environment.

The Python community has its own standards for what source code should be like,

Python社区对代码怎么写有明确的标准

codified in PEP 8

These standards are different from those of other communities,

like C, C++, C#, Java, VB, etc.

Because identation and whitespace are so important in Python,

the Style Guide for Python Code approaches a standard.

Python风格规范中把它做为了一个明确规定

It would be wise to adhere to the guide!

Most open-source projects and (hopefully) in-house projects follow the style guide quite closely.

### 空格 1 Whitespace 1

• 4 spaces per indentation level
• 4个空格组成一个缩进
• No hard tabs
• 没有制表符
• Never mix tabs and spaces
• 绝不允许制表符和空格符混用
• One blank line between functions
• 函数之间以一个空行分割
• 类之间以二个空行分割

### 空格 2 Whitespace 2

• Add a space after “,” in dicts, lists, tuples, argument lists, and after “:” in dicts, but not before
• 在”,”, lists, tuples, 参数列表，dict中的”:”后面加一个空格
• Put spaces around assignments, comparisons (except in argument lists)
• 在赋值和比较周围加入空格
• No spaces just inside parentheses or just before argument lists
• 不要在小括号或者是参数列表之前加空格
• No spaces just inside docstrings
• 不要在docstrings中加入空格
def make_squares(key, value=0):
"""Return a dictionary and a list..."""
d = {key: value}
l = {key: value}
return d, l



### 命名 Naming

• joined_lower for functions, methods, attributes
• 对函数，方法，属性统一使用小写加下划线
• joined_lower or ALL_CAPS for contrants
• 对常数使用小写加下划线或者全大写
• StudlyCaps for classes
• 对于类使用StudlyCaps
• camelCase only to conform to pre-existing conventions
• 对于已经存在的转换：camelCase
• Attributes: interface_internal__private

### 长整行及换行 Long Lines & Continuations

Keep lines below 80 characters in length

Use implied line continuation inside parentheses/brackets/braces:

def __init__(self, first, second, third,
fourth, fifth, sixth):
output = (first + second + third
+ fourth + fifth + sixth)



Use backslashes as a last resort:

VeryLong.left_hand_side \
= even_longer.right_hand_side()


Backslashes are fragile; the must end the line they’re on.

If you add a space after the backslash, it won’t work any more.

Also, they’re ugly.

### 长字符串 Long Strings

Adjacent literal strings are concatenated by the parser:

>>> print 'o' 'n' 'e'
one



The spaces between literals are not required, but help with readability. Any type of quoting can be used:

>>> print 't' r'\/\/' """o"""
t\/\/o



The string prefixed with an “r” is a “raw” string. Backslashes are not evaluated as escape in raw strings.

They’re usefual for regular expressions and Windows file system path.

Note named string objects are not concatenated.

>>> a = 'three'
>>> b = 'two'
>>> a b
File "<stdin>", line 1
a b
^
SyntaxError: invalid syntax



That is because the automatic concatenation is a feature of the Python parser/compiler,

not the interpreter. You must use the “+” to concatenate strings at run time.

The parentheses allow implicit line continuation.

text = ('Long strings can be made up '
'of several shorter strings.')



Multiline strings use triple quotes:

"""Triple
double
quotes"""

'''\
Triple
single
quotes\
'''



In the last example above (triple single quotes), note how the backslashes are used to

escape newlines. This eliminates extra newlines, while keeping the text and quotes nicely

left-justified. The backslashes must be at the end of their lines.

Compound statements

Good:

if foo == 'blah':
do_something()
do_one()
do_two()
do_three()



if foo == 'blah': do_something()
do_one(); do_two(); do_three()



Whitespace & indentations are useful visual indicators of the program flow. The indentation

of the second “Good” line above shows the reader that something’s going on, whereas the lack

of indentation in “Bad” line hides the “if” statement.

Docstrings = How to use code

Comments = Why (rationale) & how code works

Docstrings explain how to use code, and are for the users of your code.

Uses of docstrings:

- Explain the purpose of the fuction even if it seems obvious to you, because it might not be

- 解释函数的功能，即使它看起来对你显而易见，但它对后来看你的代码的人来说未必显而易见。

- obvious to someone else later on.

- Describe the parameters expected, the return values, and any exceptions raised.

- 描述期望的参数，返回值和任何可能出现的异常

- If the method is tightly coupled with a single caller, make some mention of the caller.

- 如果这个方法与调用者紧密相关，有必要提一下调用者

- (Though be careful that the caller might be changed later)

- 但要注意调用者后面可能会改变

- Comments explain why, and are for the maintainers of your code. Examples include notes to yourself, like:

- 注释是为了维护代码而写的，它解释了为什么要这样做。例如写一些note来提醒一下自己。

# !!! BUG: ...
# !!! FIX: This is a hack
# ??? Why is this here?



Both of these groups include you, so write good docstrings and comments!

Docstrings are useful in interactive use (help()) and for auto-documentation systems.

False comments & docstrings are worse than none at all.

So keep them up to date!

When you make changes, make sure the comments & docstrings are consisitent with the code,

### 实用性高于纯粹性 Practicality Beats Purity

There are always exceptions. From PEP 8:

But most importantly: know when to be inconsistent - sometimes the style guide just doesn’t apply.

When in doubt, use your best judgement. Look at other examples and decide what looks best.

Two good reasons to break a particular rule:

1. When applying the rule would make the code less readable,

even for someone who is used to reading code that follows the rules.

2. To be consisitent with surrouding code that also breaks it (maybe for historic reasons)
（也许是历史原因）与周围的代码一致也不符合规则
– although this is also an opportunity to clean up someone else’s mess.

… But practicality shouldn’t beat purity to a pulp!

### Swap Values (值互换)

In other languages: 在其它编程语言里：

temp = a
a = b
b = temp



In python: 如果用Python

b, a = a, b



Perhaps you’ve seen this before. But do you know how it works?

- The comma is the tuple constructor syntax.

- 逗号是tuple的构造语法

- A tuple is created on the right (tuple packing)

- 在等号的右边，一个tuple被创建了

- A tuple is the target on the left (tuple unpacking)

- 左边也会生成一个tuple

The right-hand side is unpacked into the names in the tuple on the left-hand side.

Further examples of unpacking:

>>> l = ['David', 'Pythonista', '+1-514-555-1234']
>>> name, title, phone = l
>>> name
'David'
>>> title
'Pythonista'
>>> phone
'+1-514-555-1234'



Useful in loops over structured data:

l above is the list we just made (David’s info). So people is a list containing two items,

l是我们上面刚建好的列表。people是一个包含两个成员的列表，每个成员又是一个3个成员的列表。

each a 3-item list.

>>> people = [l, ['guido, 'BDFL', 'unlisted']]
>>> for (name, title, phone) in people:
...     print name, phone
...
'David', '+1-514-555-1234'
'Guido', 'unlisted'



Each item in people is being unpacked into the (name, title, phone) tuple.

Arbitrarily nestable (just be sure to match the structure on the left & right!):

>>> david, (gname, gtitle, gphone) = people
>>> gname
'Guido'
>>> gtitle
'BDFL'
>>> gphone
'unlisted'
>>> david
['David', 'Pythonista', '+1-514-555-1234']



We saw that the comma is the tuple constructor, not the parentheses. Example:

>>> 1,
(1,)



The Python interpreter shows the parentheses for clarity, and I recommend you use parentheses too:

>>> (1, )
(1,)



Don’t forget the comma!

>>> (1)
1


In a one-tuple, the trailing comma is required; in 2+-tuples, the trailing comma is optional.

In 0-tuples, or empty tuples, a pair of parentheses is the shortcut syntax:

>>> ()
()
>>> tuple()
()



A common typo is to leave a comma even though you don’t want a tuple. It can be easy to miss in your code.

>>> value = 1,
>>> value
(1,)



So if you see a tuple where you don’t expect one, look for a comma!

### 用在交互窗口使用的”” Interactive “”

This is a really useful feature that surprisingly few people know.

In the interactive interpreter, whenever you evaluate an expression or call a function,

the result is bound to a temporary name, _(underscore).

>>> 1 + 1
2
>>> _
2



_ stores the last printed expression.

_ 保存了上一次被打印的表达式的值。

When a result is None, nothing is printed, so _ doesn’t change. That’s convinenient!

This only works in the interactive interpreter, not within a modoule.

It is especially useful when you’re working out a problem interactively,

and you want to store the result for a later step.

>>> import math
>>> math.pi / 3
1.0471975511965976
>>> angle = _
>>> math.cos(angle)
0.50000000000000011
>>> _
0.50000000000000011



### 用子串构建字符串 Building Strings from Substrings

colors = ['red', 'blue', 'green', 'yellow']


We want to join all the strings together into one large string.

Especially when the number of substrings is large…

Don’t do this:

result = ''
for s in colors:
result += s



This is very inefficient.

It has terrible memory usage and performance patterns. The ‘summation” will compute,

store, and then throw away each intermediate step.

result = ''.join(colors)



When you are only dealing with a few dozen or hundred strings, it won’t make much difference.

But get in the habit of building strings efficiently, because with thousands or with loops, it will make a difference.

### 构建字符串 Building Strings, Variations 1

Here are some techniques to use the join() string method.

If you want spaces between your substrings:

result = ' '.join(colors)



Or commas and spaces:

result = ', '.join(colors)



Here’s a common case:

colors = ['red', 'blue', 'green', 'yellow']
print 'Choose', ', '.join(colors[:-1]), \
'or', colors[-1]



To make a nicely grammatical sentence, we want commas between all but the last pair of values,

where we want the word ‘or’. The slice syntax does the job.

The “slice until -1”([:-1]) gives all but the last value, which we join with comma-space.

“slice until -1” ([:-1]) 可以帮助你在用逗号和空格连接时提供除了最后一组外的所有单词。

Of course, this code wouldn’t work with corner cases, lists of length 0 or 1.

Output:

Choose red, blue, green or yellow



### 构建字符串 Building Strings, Variations 2

If you need to apply a function to generate the substrings:

result = ''.join(fn(i) for i in items)



This involves a generator expression, which we’ll cover later.

If you need to compute the substrings incrementally, accumulate them in a list first:

items = []
...
items.append(item) # many times
...
# items is now complete
result = ''.join(fn(i) for i in items)



We accumulate the parts in a list so that we can apply the join string method, for efficiency.

### 尽可能的用关键字 “in” Use in where possible (1)

Good:

for key in d:
print key


• in is generally faster
• in 通常会更快
• This pattern also works for items in arbitrary containers(such as lists, tuples, and sets)
• 这个模式对于其它的一些容器也适用，如lists, tuples, sets
• in is also an operator (as we’ll see)
• in 也是一个操作符

for key in d.keys():
print key



This is limited to objects with a keys() method.

### 尽可能的用”in”(2) Use in where possible （2）

But .keys() is necessary when mutating the dictionary:

for key in d.keys():
d[str(key)] = d[key]



d.keys() creates a static list of the dictionary keys. Otherwise, you’ll get an expression

d.keys() 会创建一个由所有keys组成的静态的列表。否则，你会得到以下错误：

“RuntimeError: dictionary changed size during iteration”.

“运行时错误，字典的大小在遍历时发生变化”

For consistency, use key in dict, not dict.has_key()

# do this
if key in d:
do something with d[key]

# not this
if d.has_key(key):
do something with d[key]



### 字典的get方法 Dictionary get Method

We often has to initialize dictionary entries before use:

This is a naive way to do it:

navs = {}
for (portfolio, equity, position) in data:
if portfolio not in navs:
navs[portfolio] = 0
navs[portfolio] += position * prices[equity]



dict.get(key, default) removes the need for the test:

dict.get(key, default) 可以省掉这样的测试语句。

navs = {}
for (portfolio, equity, position) in data:
navs[portfolio] = (navs.get(portfolio, 0)
+ position * prices[equity]



Much more direct。

### 字典中的”setdefault”方法（1） Dictionary setdefault Method (1)

Here we have to initialize mutable dictionary values. Each dictionary value will be a list.

Initializing mutable dictionary values:

equities = {}
for (portfolio, equity) in data:
if portfolio in equities:
equities[portfolio].append(equity)
else:
equities[portfolio] = [equity]



dict.setdefault(key, default) does the job much more efficiently

dict.setdefault(key, default) 可以更高效地实现这一点

equities = {}
for (portfolio, equity) in data:
equities.setdefault(portfolio, []).append(equity)



dict.setdefault() is equivalent to “get, or set & get”. Or “set if necessary, then get”.

dict.setdefault() 相当于 “get, or set & get”. 或者 “set if necessary, then get”.

It’s especially efficient if your dictionary key is expensive to compute or long to type.

The only problem with dict.setdefault() is that the default value is always evaluated, whether needed or not.

dict.setdefault()唯一的问题就是永运会计算默认值，不管需不需要。

That only matters if the default value is expensive to compute.

If the default value is expensive to compute, you may want to use the defaultdict class, which we’ll cover shortly.

### 字典中的“setdefault”方法（2） Dictionary setdefault Method (2)

Here we see that the setdefault dictionary method can also be used as a stand-alone statement:

navs = {}
for (portfolio, equity, position) in data:
navs.setdefault(portfolio, 0)
navs[portfolio] += position * prices[equity]



The setdefault dictionary method returns the default value, but we ignore it here.

setdefault方法返回了默认值，但我们却忽略了它。

We’re taking advantage of setdefault’s side effect,

that it sets the dictionary value only if there is no value already.

### defaultdict

New in Python 2.5

Python 2.5中的新功能

defaultdict is new in Python 2.5, part of the collections module.

defaultdict作为collections模块的一部门，是Python 2.5中的新功能。

defaultdict is identical to regular dictionaries, except for two things:

defaultdict 在除了以下两点之外与通常的字典相同

- it takes an extra first argument: a default factory function; and

- 它多接收一个参数：一个默认值工厂函数

- when a dictionary key is encountered for the first time, the default factory function is called and the result used to initialize the dictionary value.

- 当字典中的key第一次出现的时候，默认值工厂函数会被调用来给这个key赋值。

There are two ways to get defaultdict

- import the collections modoule and reference it via the module

import collections
d = collections.defaultdict(...)


• or import the defaultdict name directly
from collections import defaultdict
d = defaultdict(...)



Here’s the example from earlier, where each dictionary value must be initialized to an empty list, rewritten as with defaultdict:

from collections import defaultdict
equities = defaultdict(list)
for (portfolio, equity) in data:
equities[portfolio].append(equity)



There’s no fumbling around at all now. In this case, the default factory function is list

which returns an empty list.

This is how to get a dictionary with default values of 0: use int as a default factory function:

navs = defaultdict(int)
for (portfolio, equity, position) in data:
navs[portfolio] += position * prices[equity]



You should be careful with defaultdict though.

You cannot get KeyError exceptions from properly initialized defaultdict instances.

You have to use a “key in dict” conditional if you need to check for the existence of a special key.

### 构建和拆分字典 Building & Splitting Dictionaries

Here is a useful technique to build a dictionary from two lists(or sequences):

one list of keys, another list of values

given = ['John', 'Eric', 'Terry', 'Michael']
family = ['Cleese', 'Idle', 'Gilliam', 'Palin']
pythons = dict(zip(given, family))
>>> pprint.pprint(pythons)
{'John': 'Cleese',
'Michael': 'Palin',
'Eric': 'Idle',
'Terry': 'Gilliam'}



The reverse, of course, is trival:

>>> pythons.keys()
['John', 'Michael', 'Eric', 'Terry']
>> pythons.values()
['Cleese', 'Palin', 'Idle', 'Gilliam']



Note that the order of the results of keys() and values() is different from the order of items

when constructing the dictionary. The order going in is different from the order coming out.

This is because a dictionary is inherently unordered. However, the order is guaranteed to be consisitent

(in other words, the order of keys will correspond to the order of values),

as long as the dictionary isn’t changed between calls.

### 检查真值 Testing for Truth Values

# do this:      # not this:
if x:           if x == True:
pass            pass



It is elegant and efficient to take advantage of the intrinsic truth values

(or Boolean values) of Python objects.

Testing a list:

# do this                   # not this:
if items:                   if len(items) != 0:
pass                        pass
# and definitely not this:
if items != []:
pass



### 真值 Truth Values

The True and False names are build-in instances of type bool， Boolean values.

TrueFalse是内建的bool实例

Like None, there is only one instance of each.

|False |True |

|False(==0) |True(==1) |

|”“(empty string) |any string but “” (” “, “anything”) |

|0, 0.0 |any number but 0 (1, 0.1, -1, 3.14) |

|[], (), {}, set() |any none empty container |

|None |almost any object taht’s not explicitly False |

Example of an object’s truth value:

>>> class C:
...     pass
...
>>> o = C()
>>> bool(o)
True
>>> bool(C)
True



To control the truth value of instances of a user-defined class,

use the nonezero or len special methods, Use len if your container which has a length.

class MyContainer(object):
def __init__(self, data):
self.data = data

def __len__(self):
''' Return my length '''
return len(self.data)



If your class is not a container, use nonezero

class MyClass(object):
def __init__(self, value):
self.value = value

def __nonezero__(self):
Return my truth value (True or False)
return bool(self.value)



In Python 3.0, nonezero has been renamed to bool for consistency with the bool built-in type.

For compatibility, add this to the class definition:

__bool__ = __nonezero__
1


### 索引和成员（1） Index & Item (1)

Here’s a cute way to save some typing if you need a list of words:

>>> items = 'zero one two three'.split()
>>> print items
['zero', 'one', 'two', 'three']



Say we want to interate over the items, and we need both the item’s index and the item itself:

i = 0
for item in items:      for i in range(len(items)):
print i, item           print i, items[i]
i += 1



We need to use a list wrapper to print the result because enumerate is a lazy function:

it generates one item, a pair, at a time, only when required.

for loop is one place that requires one result at a time. enumerate is an example of a generator,

for循环是一个一次只要一个结果的地方，enumerate是一个生成器的例子,

which we’ll cover in greater detail later.

print does not take one result at a time –

print并非一次只取一个结果

we want the entire result, so we have to explicitly convert the generator into a list when we print it.

Our loop becomes much simpler:

for (index, item) in enumerate(items):
print index, item

# compare                       # compare
index = 0                       for i in range(len(items)):
for item in items:                  print i, items[i]
print index, item
index += 1



The enumerate version is much shorter and simpler than the version on the left,

enumerate版本的代码比起左边的代码来要更简单易读，且容易理解

and much easier to read and understand than earlier.

An example showing how the enumerate function actually returns an iterator (a generator is a kind of iterator):

>>> enumerate(items)
<enumerate object at 0x011EA1C0>
>>> e = enumerate(items)
>>> e.next()
(0, 'zero')
>>> e.next()
(1, 'one')
>>> e.next()
(2, 'two')
>>> e.next()
(3, 'three')
>>> e.next()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
StopIteration



### Other language have “variables”

In many other languages, assigning to a variable puts a value into a box.

int a = 1;



Box “a” now contains an integer 1.

Assigning another value to the same variable replaces the contents of the box:

int a = 2;



Now box “a” contains an integer 2.

Assigning one variable to another makes a copy of the value and puts it in the new box:

int b = a;



“b” is a second box, with a copy of integer 2. Box “a” has a separate copy.

“b”就是第2个盒子，它拥有整数2的一个拷贝，与盒子”a”中的是不同的一份。

### Python中的名字 Python has “names”

In Python, a “name” or “identifier” is like a parcel tag (or nametag) attached to an object.

a = 1



Here, an integer 1 object has a tag labelled “a”.

If we reassign to “a”, we just move the tag to another object:

a = 2



Now the name “a” is attached to an integer 2 object.

The original integer 1 object no longer has a tag “a”. It may live on,

but we can’t get to it through the name “a”.

If we assign one name to another, we’re just attaching another nametag to an existing object:

b = a



The name “b” is just a second tag bound to the same object as “a”.

“b”和”a”都指向了同一个对象，只是名字不同而已

Although we commonly refer to “variables” evne in Python (because it’s common terminology),

we really means “names” or “identifiers”. In Python, “variables” are nametags for values, not labelled boxes

### 默认参数值 Default Parameter Values

This is a common mistake that beginners often make.

Even more advanced programmers make this mistake if they don’t understand Python names.

def bad_append(new_item, a_list=[]):
a_list.append(new_item)
return a_list



The problem here is the default value of a_list, an empty list, is evaluated at function definition time.

So every time you call the function, you get the same default value. Try it several times:

>>> print bad_append('one')
['one']
['one', 'two']



Lists are a mutable objects; you can change their contents. The correct way to get a default list

(or dictionary, or set) is to create it at run time instead, inside the function:

def good_append(new_item, a_list=None):
if a_list is None:
a_list = []
a_list.append(new_item)
return a_list



### “%”字符串格式化 % String Formatting

Python’s % operator works like C’s sprintf function

Python的 % 操作符和C语言的sprintf函数一样

Although if you don’t know C, that’s not very helpful.

Basically, you provide a template or format and interpolation values.

In this example, the template contains two conversion specifications: “%s” means

“insert a string here”, and “%i” means “convert an integer to a string and insert here”.

“%s” is particularly useful because it uses Python’s build-in str() function to convert any object to a stirng.

“%s”尤其有用，因为它使用了Python的内建str()函数来将任意的对象转换成字符串

The interpolation values must match the template; we have two values here, a tuple.

name = 'David'
message = 3
text = ('Hello %s, you have %i message'
% (name, message))
print text



Output:

Hello David, you have 3 messages



### 高级”%”字符串格式化 Advanced % String Formatting

What many people don’t realize is that there are other, more flexible ways to do string formatting:

By name with a dictionary:

values = {'name':name, 'messages':messages}
print ('Hello %(name)s, you have %(messages)i messages' % values)



Here we specify the names of interpolation values, which are looked up in the supplied dictionary.

Note: Class attributes are in the class dict. Namespace lookups are actually chained dictionary lookups.

### 列表推导 List Comprehensions

List comprehensions (“listcomps” for short) are syntax shortcuts for this general pattern:

The traditional way, with for and if statements:

new_list = []
for item in a_list:
if condition(item):
new_list.append(fn(item))



As a list comprehension:

new_list = [fn(item) for item in a_list if condition(item)]



Listcomps are clear & concise, up to a point.

You can have multiple for-loops and if-conditions in a listcomp, but beyond two or three total,

or if the conditions are complex, I suggest that regular for loops should be used.

Applying the Zen of Python, choose the more readable way.

For example, a list of the squares of 0-9:

>>> [n ** 2 for n in range(10)]



A list of the squares of odd 0-9:

0-9中奇数的平方所组成的列表

>>> [n ** 2 for n in range(10) if n % 2]



### 生成器表达式（1） Generator Expressions(1)

Let’s sum the squares of the numbers up to 100:

As a loop:

total = 0
for num in range(1, 101):
total += num * num



We can use sum function to quickly do the work for us, by building the appropriate sequence.

As a list comprehension

total = sum([num * num for num in range(1, 101)])



As a generator expression:

total = sum(num * num for num in xrange(1, 101))



Generator expressions(“genexps”) are just like list comprehensions, except that where listcomps are greedy,

generator expressions are lazy. Listcomps compute the entire result list all at once, as a list.

Generator expressions compute one value at a time, when needed, as individual values.

This is especially useful for long sequences where the computed list is just an intermediate step and not the final result.

In the case, we’re only interested in the sum; we don’t need the intermediate list of squares.

We use xrange for the same reason: it lazily produces values, one at a time.

### 生成器表达式（2） Generator Expressions(2)

For example, if we were summing the squares of several billion integers,

we’d run out of memory with list comprehensions, but generator expressions have no problem.

This does take time, though!

total = sum(num * num
for num in xrange(1, 1000000000))



The difference in syntax is that listcomps have square brackets, but generator expressions don’t.

Generator expressions sometimes do require enclosing parentheses though, so you should always use them.

Rules of thumb:

- Use a list comprehension when a computed list is the desired end result

- 如果运算出来的列表是最终结果，那么请使用列表推导

- Use a generator expression when the computed list is just an intermediate step.

- 如果运算出来的列表只是中间步骤，那么请使用生成器表达器

We needed a dictionary mapping month numbers(both as string and as integers) to month codes for futures contracts.

The way this works is as follows:

- The dict() built-in takes a list fo key/value pairs(2-tuples).

- We have a list of month codes (each month code is a single letter, and a string is also just a list of letters).

We enumerate over this list to get both the month code and the index

- The month numbers start at 1, but Python starts indexing at 0, so the month number is one more than the index.

- We want to look up months both as strings and as integers. We can use int() and str() functions to do this for us,

and loop over them.

Recent example:

month_codes = dict((fn(i+1), code)
for i, code in enumerate('FGHJKMNQUVXZ')
for fn in (int, str))



month_codes result:

{ 1: 'F', 2: 'G', 3: 'H', 4: 'J', ...
'1': 'F', '2': 'G', '3': 'H', '4': 'J', ...}



### 排序 Sorting

It’s easy to sort a list in Python

a_list.sort()



(Note that the list is sorted in-place: the original list is sorted,

and the sort method does not return the list or a copy.

But what if you have a list of data that you need to sort, but it doesn’t sort naturally?

(i.e., sort on the first column, then the second column, etc.)

You man need to sort on the second column first, then the fourth column.

We can use list’s built-in sort method with a custom function.

def custom_cmp(item1, item2):
return cmp((item1[1], item1[3]),
(item2[1], item2[3]))
a_list.sort(custom_cmp)



This works, but it’s extremely slow for large lists.

### Sorting with DSU *

DSU = Decorate-Sort-Undecorate

* Note: DSU is often on longer necessary. See the next section, Sorting With Keys for the new approach.

Instead of creating a custom comparison function, we create an auxiliary list that will sort naturally:

# Decorate
to_sort = [(item[1], item[3], item)
for item in a_list]
# Sort
to_sort.sort()

# Undecorate
a_list = [item[-1] for item in to_sort]



The first line creates a list containing tuples: copies of the sort terms in priority order,

followed by the complete data record.

The second line does a native Python sort, which is very fast and efficient.

The third line retrieves the last value from the sorted list.

Remember, this last value is the complete data record.

We’re throwing away the sort terms, which ahve done their job and are no longer needed.

This is a tradeoff of space and complexity against time.

Much simpler and faster, but we do need to duplicate the original list.

### 值排序 Sorting With Keys

Python 2.4 introduced an optional argument to the sort list method,

Python 2.4 为sort方法引入一个可选参数 “key”

“key”, which specifies a function of one argument that is used to compute a comparison key from each list element.

def my_key(item):
return (item[1], item[3])

to_sort.sort(key=my_key)



The function my_key will be called once for each item in the to_sort list.

You can make your own key function, or use any existing one-argument function if applicable.

- str.lower to sort alphabetically regardless of case

- 忽略大小写排序， str.lower

- len to sort on the length of the items (strings or containers)

- 按长度排序，len

- int or float to sort numerically, as with numeric strings like “2”, “123”, “35”

- 按数值的大小排序，int, float

### 生成器 Generators

We can devise our own arbitrarily complex generators, as functions:

def my_range_generator(stop):
value = 0
while value < stop:
yield value
value += 1

for i in my_range_generator(10):
do_something(i)



The yield keyword turns a function into a generator. When you call a generator function,

yield关键字把一个函数转换成一个生成器。当你调用一个生成器函数的时候，

instead of running the code immediately Python returns a generator object;

Python把它变成了一个生成器对象而不是立即去执行

it has next method. for loops just call the next method on the iterator, until a StopIteration exception is raised.

You can raise StopIteration explicitly, or implicitly by falling off the end of the generator code as above.

Generators can simplify sequence/iterator handling, because we don’t need to build concrete lists;

just compute one value at a time. The generator function maintains state.

This is how a for loop really works. Python looks at the sequence supplied after the in keyword.

If it’s a simple container (such as a list, tuple, dictionary, set, or user-defined container) Python converts it into an iterator.

If it’s already an iterator, Python does nothing.

The python repeatedly calls the iterator’s next method, assigns the return value to the loop counter(i in this case),

Python不停地调用迭代器的next方法，把返回值赋值给循环计数器(在这个例子中是i

and executes the intended code.

This is repeated over and over, until StopIteration is raised, or a break statement is executed in the code.

for loop can have an else clause, whose code is executed after the iterator runs dry,

for循环可以有一个else子句，用于当迭代器一直执行到溢出时执行

but not after a break statement is executed.

This distinction allows for some elegant uses. else clauses are not always or often used on for loops,

but they can come in handy.

Somtimes the else clause perfectly expresses the logic you need.

For example, if we need to check that a condition holds on some item, any item, in a sequence:

for item in sequence:
if condition(item):
break
else:
raise Exception('Condition not satisfied.')



### 生成器例子 Example Generator

Filter out blank rows from a CSV reader (or items from a list):

def filter_rows(row_iterator):
for row in row_iterator:
if row:
yield row

data_file = open(path, 'rb')



### 逐行读取文本文件 Reading Lines From Text/Data Files

datafile = open('datafile')
for line in datafile:
do_something(line)



This is possible because files support a next method, as do other iterators: lists, tuples,

dictionaries(for their keys), generators.

### EAFP vs. LBYL

EAFP: It’s easier to ask forgiveness than permission.

Generally EAFP if preferred, but not always.

EAFP通常更容易，但并不总是这样

- Duck typing

If it walks like a duck, and talks like a duck, and looks like a duck: it’s a duck.

- Exceptions

Use coercion if a object must be a particular type. If x must be a string for your code to work, why not call

str(x)



isinstance(x, str)



### EAFP try/except example

You can wrap except-prone code in try/except block to catch the errors,

and you will probably end up with a solution that’s much more general than if you had tried to anticipate every possibility.

try:
return str(x)
except TypeError:
...



Note: Always specify the error to catch. Never use bare except clause.

Bare except clause will catch unexpected exceptions, making your code exceedingly difficut to debug.

### 导入 Importing

from module import *



You have probably seen this ‘wild card’ form of the import statement.

You may even like it. Don’t use it.

To paraphase a well-known exchange:

LUKE: Is from module import * better than explicit imports?

YODA: No, not better. Quicker, easier, more seductive.

LUKE: But how will I know why explicit imports are better than wild-card form?

YODA: Know you will when your code you try to read six months fron now.

Wild-card imports are from the dark side of Python.

Wild-card imports来自Python的黑暗面。

The from module import * wild-card style leads to namespace pollution.

You may see imported names obscuring module-defined local names.

You won’t be able to figure out where certain names come from.

Although a convinenient shortcut, this should not be in production code.

Moral: Don’t wild-card imports!

It’s much better to:

- reference names through their module (fully qualified identifier)

- 通过模块来引用名字

- import a long module using a shorter name (alias, recommend）

- 把它import成更简短的名字，别名

- or explicitly import just the names your need.

- 或者直接只import你要用的名字

Reference names through their module (fully qualified identifier)

import module
module.name



Or import a long module using a shorter name (alias)

import long_module_name as mod
mod.name



Or explicitly import just the names you need:

from module import name
name



Note that this form doesn’t lend itself to use in the interactive interpreter, where you may want to edit and “reload()” a module.

### 模块与脚本 Modules & Scripts

To make a simutaneously importable module and executable script:

if __name__ == '__main__':
# script code here



When imported, the module’s __name__ attribute is set to the module’s file name, without ‘.py’.

So the code guarded by the if statement will not run when imported. When executed as a script though,

the name attribute is set to “main“, and the script code will run.

### 模块结构 Module Structure

"""module docstring"""
# imports
# constants
# exception classes
# interface functions
# classes
# internal functions & classes

def main(...):
...

if __name__ == '__main__':
status = main()
sys.exit(status)



### 命令行处理 Command-Line Processing

#!/usr/bin/env python
"""
Module docstring.
"""

import sys
import optparse

def process_command_line(argv):
"""
Return a 2-tuple: (settings object, args list).
argv is a list of arguments, or None for sys.argv[1:].
"""
if argv is None:
argv = sys.argv[1:]

# initialize the parser object:
parser = optparse.OptionParser(
formatter=optparse.TitledHelpFormatter(width=78),

# define options here:
parser.add_option( # customized description; put --help last
'-h', '--help', action='help',
help='Show this help message and exit.')

settings, args = parser.parse_args(argv)

# check number of arguments, verify values, etc.:
if args:
parser.error('program takes no command-line arguments; '
'"%s" ignored.' % (args,))

# further process settings & args if necessary

return settings, args

def main(argv=None):
settings, args = process_command_line(argv)
# application code here, like:
# run(settings, args)
return 0 # success

if __name__ == '__main__':
status = main()
sys.exit(status)



### 包 Packages

package/
__init__.py
module1.py
subpackage/
__init__.py
module2.py


• Used to organize your project
• 用于组织项目
• Reduces import name conflicts
• 减少命名冲突

Example:

import package.module1
from packages.subpackage import module2
from packages.subpackage.module2 import name
from __future__ import absolute_import



I haven’t delved into these myself yet, so we’ll conveniently cut this discussion short.

### 简单好于复杂 Simple is better than complex

Debugging is twice hard as writing the code in the first place.

Therefore, if you write your code as clearly as possible,

you are, by definition, not smart enough to debug it.

In other words, keep your programs simple.

### 不要重新发明轮子 Don’t reinent the wheel

- Check Python’s standard library

- 查看标准库中有没有你想要的库

- Check the Python Package Index (http://cheeseshop.python.org/pypi

- 检查Python包的索引