我一辈子都在写代码,但从来没有掌握编码的精髓。大部分情况下使用Visual Basic,因为我用VB最舒服。同时还略微了解一点其他语言(R、C、JavaScript、Applescript、Hypertext和1979年学习的BASIC)。几年前,我决定只用Python,以此来提高我的编码能力。在此过程中重复发明了许多轮子,但我并不介意,因为我享受解决问题的乐趣。同时有时能发现更有效、Python式的解决方案。时间长了以后,会有顿悟的时刻,意识到根本没必要用困难且冗长的方式处理问题。下面列出10条Python用法,如果我早点发现,也许能节省很多时间。
这里没有列表推导和lambda函数。虽然这两个用法都是Python式的,效率高也非常酷,但由于经常在StackOverflow或其他地方碰到,所以学Python的应该都知道这两个东西。同时也没有三元运算符、装饰器和生成器,因为我很少用到。
本文还有一个IPython notebook nbviewer版本。
1. 在Python 2中使用Python 3式的输出
Python 2与Python 3不兼容,这让我不知道该选择哪个版本的Python。最终我选择了Python 2,因为当时许多我需要用的库都与Python 3不兼容。
但实际上,日常使用中最大的版本差异是输出(print)和除法行为。现在我在Python 2的代码中都用import from future来导入Python 3的输出和除法。现在我用到的几乎所有库都支持Python 3,因此会很快迁移到Python 3中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
mynumber
=
5
print
"Python 2:"
print
"The number is %d"
%
(
mynumber
)
print
mynumber
/
2
,
print
mynumber
/
/
2
from
__future__
import
print_function
from
__future__
import
division
print
(
'nPython 3:'
)
print
(
"The number is {}"
.
format
(
mynumber
)
)
print
(
mynumber
/
2
,
end
=
' '
)
print
(
mynumber
/
/
2
)
|
1
2
3
|
Python
2
:
The
number
is
5
2
2
|
1
2
3
|
Python
3
:
The
number
is
5
2.5
2
|
对了,对于C系的那些更喜欢括号而不是缩进的开发者,这里还有一个彩蛋:
1
2
3
4
|
from
__future__
import
braces
File
""
,
line
1
from
__future__
import
braces
SyntaxError
:
not
a
chance
|
2. enumerate(list)
很明显,迭代列表时,应该同时迭代其中的元素及其索引,但在很长一段时间内,我都尴尬的使用计数变量或切片。
1
2
3
4
|
mylist
=
[
"It's"
,
'only'
,
'a'
,
'model'
]
for
index
,
item
in
enumerate
(
mylist
)
:
print
(
index
,
item
)
|
1
2
3
4
|
0
It'
s
1
only
2
a
3
model
|
3. 链式比较操作符
由于我以前使用的是静态语言(在这些语言中该用法有二义性),从来没有将两个比较操作符放在一个表达式中。在许多语言中,4 > 3 > 2会返回False,因为4 > 3的结果是布尔值,而True > 2将得出False。
1
2
3
4
|
mynumber
=
3
if
4
>
mynumber
>
2
:
print
(
"Chained comparison operators work! n"
*
3
)
|
1
2
3
|
Chained
comparison
operators
work
!
Chained
comparison
operators
work
!
Chained
comparison
operators
work
!
|
4. collections.Counter
Python的集合库看上去是最好的。在计算需要集合中元素的个数时,StackOverflow找到的答案是创建有序字典,但我坚持使用一个代码片段来创建字典,计算结果中元素出现的频率。直到有一天,我发现可以用collections.deque。
1
2
3
4
5
6
7
8
9
10
11
12
|
from
collections
import
Counter
from
random
import
randrange
import
pprint
mycounter
=
Counter
(
)
for
i
in
range
(
100
)
:
random_number
=
randrange
(
10
)
mycounter
[
random_number
]
+=
1
for
i
in
range
(
10
)
:
print
(
i
,
mycounter
[
i
]
)
|
1
2
3
4
5
6
7
8
9
10
|
0
10
1
10
2
13
3
6
4
6
5
11
6
10
7
14
8
12
9
8
|
5. 字典推导
Python开发者的一个重要标志就是理解列表推导,但最终我发现字典推导也很有用,特别是在交换字典的键和值的时候。
1
2
3
4
5
|
my_phrase
=
[
"No"
,
"one"
,
"expects"
,
"the"
,
"Spanish"
,
"Inquisition"
]
my_dict
=
{
key
:
value
for
value
,
key
in
enumerate
(
my_phrase
)
}
print
(
my_dict
)
reversed_dict
=
{
value
:
key
for
key
,
value
in
my_dict
.
items
(
)
}
print
(
reversed_dict
)
|
1
2
|
{
'Inquisition'
:
5
,
'No'
:
0
,
'expects'
:
2
,
'one'
:
1
,
'Spanish'
:
4
,
'the'
:
3
}
{
0
:
'No'
,
1
:
'one'
,
2
:
'expects'
,
3
:
'the'
,
4
:
'Spanish'
,
5
:
'Inquisition'
}
|
6. 用subprocess执行shell命令
以前,我使用os库调用外部命令处理文件,而现在我可以在Python中以编码的方式执行诸如ffmpeg这样的复杂命令进行视频编辑。
(是的,我和我的客户都使用Windows,如果你们因此鄙视我,我会大方地接受!)
注意,用os库完成这个特定命令比用subprocess更好。我只想有一个大家都熟悉的命令。同时,一般来说,在subprocess中使用shell=True参数是非常糟糕的主意,在这里使用这个参数仅仅是为了能在一个IPython notebook单元中放置命令的输出。不要自己使用这个参数!
1
2
3
|
import
subprocess
output
=
subprocess
.
check_output
(
'dir'
,
shell
=
True
)
print
(
output
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Volume
in
drive
C
is
OS
Volume
Serial
Number
is
[
REDACTED
]
Directory
of
C
:
UsersDavidDocuments
[
REDACTED
]
2014
-
11
-
26
06
:
04
AM
<
DIR
>
.
2014
-
11
-
26
06
:
04
AM
<
DIR
>
.
.
2014
-
11
-
23
11
:
47
AM
<
DIR
>
.
git
2014
-
11
-
26
06
:
06
AM
<
DIR
>
.
ipynb
_checkpoints
2014
-
11
-
23
08
:
59
AM
<
DIR
>
CCCma
2014
-
09
-
03
06
:
58
AM
19
,
450
colorbrewdict
.
py
2014
-
09
-
03
06
:
58
AM
92
,
175
imagecompare
.
ipynb
2014
-
11
-
23
08
:
41
AM
<
DIR
>
Japan
_Earthquakes
2014
-
09
-
03
06
:
58
AM
1
,
100
LICENSE
2014
-
09
-
03
06
:
58
AM
5
,
263
monty_monte
.
ipynb
2014
-
09
-
03
06
:
58
AM
31
,
082
pocket_tumblr_reddit_api
.
ipynb
2014
-
11
-
26
06
:
04
AM
3
,
211
README
.
md
2014
-
11
-
26
06
:
14
AM
19
,
898
top_10_python_idioms
.
ipynb
2014
-
09
-
03
06
:
58
AM
5
,
813
tree_convert_mega_to_gexf
.
ipynb
2014
-
09
-
03
06
:
58
AM
5
,
453
tree_convert_mega_to_json
.
ipynb
2014
-
09
-
03
06
:
58
AM
1
,
211
tree_convert_newick_to_json
.
py
2014
-
09
-
03
06
:
58
AM
55
,
970
weather_ML
.
ipynb
11
File
(
s
)
240
,
626
bytes
6
Dir
(
s
)
180
,
880
,
490
,
496
bytes
free
|
7. 字典的.get()和.iteritems()方法
字典的get()方法可以设置默认值,当用get()查找的键不存在时,返回方法中的默认值参数是很有用的。与列表中的enumerate()相同,可以用键值元组迭代字典中的元素。
1
2
3
4
5
6
|
my_dict
=
{
'name'
:
'Lancelot'
,
'quest'
:
'Holy Grail'
,
'favourite_color'
:
'blue'
}
print
(
my_dict
.
get
(
'airspeed velocity of an unladen swallow'
,
'African or European?n'
)
)
for
key
,
value
in
my_dict
.
iteritems
(
)
:
print
(
key
,
value
,
sep
=
": "
)
|
1
|
African
or
European
?
|
1
2
3
|
quest
:
Holy
Grail
name
:
Lancelot
favourite_color
:
blue
|
8. 用于交换元素的元组解包
在VB中,每当需要交换两个变量时,都要用要一个愚蠢的临时变量:c = a; a = b; b = c
1
2
3
4
5
6
7
8
|
a
=
'Spam'
b
=
'Eggs'
print
(
a
,
b
)
a
,
b
=
b
,
a
print
(
a
,
b
)
|
1
2
|
Spam
Eggs
Eggs
Spam
|
9. 内省工具Introspection tools
我知道dir()方法,我本以为help()方法和IPython中的?魔法命令是一样的,但help()的功能更强大。
1
2
3
|
my_dict
=
{
'That'
:
'an ex-parrot!'
}
help
(
my_dict
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
Help
on
dict
object
:
class
dict
(
object
)
|
dict
(
)
->
new
empty
dictionary
|
dict
(
mapping
)
->
new
dictionary
initialized
from
a
mapping
object
's
| (key, value) pairs
| dict(iterable) -> new dictionary initialized as if via:
| d = {}
| for k, v in iterable:
| d[k] = v
| dict(**kwargs) -> new dictionary initialized with the name=value pairs
| in the keyword argument list. For example: dict(one=1, two=2)
|
| Methods defined here:
|
| __cmp__(...)
| x.__cmp__(y) <==> cmp(x,y)
|
| __contains__(...)
| D.__contains__(k) -> True if D has a key k, else False
|
| __delitem__(...)
| x.__delitem__(y) <==> del x[y]
|
| __eq__(...)
| x.__eq__(y) <==> x==y
|
[TRUNCATED FOR SPACE]
|
| update(...)
| D.update([E, ]**F) -> None. Update D from dict/iterable E and F.
| If E present and has a .keys() method, does: for k in E: D[k] = E[k]
| If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
| In either case, this is followed by: for k in F: D[k] = F[k]
|
| values(...)
| D.values() -> list of D'
s
values
|
|
viewitems
(
.
.
.
)
|
D
.
viewitems
(
)
->
a
set
-
like
object
providing
a
view
on
D
's items
|
| viewkeys(...)
| D.viewkeys() -> a set-like object providing a view on D'
s
keys
|
|
viewvalues
(
.
.
.
)
|
D
.
viewvalues
(
)
->
an
object
providing
a
view
on
D'
s
values
|
|
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
--
|
Data
and
other
attributes
defined
here
:
|
|
__hash__
=
None
|
|
__new__
=
|
T
.
__new__
(
S
,
.
.
.
)
->
a
new
object
with
type
S
,
a
subtype
of
T
|
10. PEP-8兼容的字符串连接
PEP8是Python编码样式指南。撇开其他的不看,PEP8要求每行不能超过80个字符,超过的部分要换行并缩进。
可以通过反斜杠、带逗号“,”的圆括号“()”、或者额外的加号“+”来完成换行。但对于多行字符串,这些解决方案都不够优雅。Python有个多行字符串记号,即三个引号,但这样无法换行后保持缩进。
还有一个方法,那就是不带逗号的圆括号。我不知道为什么这种方式能工作,但能用就行。
1
2
3
4
|
my_long_text
=
(
"We are no longer the knights who say Ni! "
"We are now the knights who say ekki-ekki-"
"ekki-p'tang-zoom-boing-z'nourrwringmm!"
)
print
(
my_long_text
)
|
1
|
We
are
no
longer
the
knights
who
say
Ni
!
We
are
now
the
knights
who
say
|