- Item1:確認(rèn)python版本(由于2失去官方支持了,強(qiáng)制要求使用3):
python3 --version
或者
import sys
print(sys.version_info)
print(sys.version)
- Item2:使用PEP8的風(fēng)格來(lái)寫(xiě)代碼:
用空格來(lái)分隔,4個(gè)空格來(lái)分語(yǔ)法句
每行不應(yīng)超過(guò)79個(gè)字符
長(zhǎng)表達(dá)式應(yīng)該分隔開(kāi)語(yǔ)義便于理解
一個(gè)文件內(nèi),函數(shù)和類應(yīng)該用兩個(gè)空行分隔
一個(gè)類內(nèi),方法應(yīng)該用一個(gè)空行分隔
字典中,key和:之間沒(méi)有空格,:和value之間有一個(gè)空格(如果在同一行)
=號(hào)前后加一個(gè)空格
-
在明確變量的類型時(shí),變量名與:沒(méi)有空格,:和變量類型名之間有一個(gè)空格
命名: 函數(shù)和變量,用lowercase_underscore命名
受保護(hù)的實(shí)例變量,用_leading_underscore命名
__double_leading_underscore格式
模塊級(jí)的常量應(yīng)該用ALL_CAPS格式
-
實(shí)例函數(shù)用self作為第一個(gè)參數(shù)變量,類方法用cls作為第一個(gè)參數(shù)變量。
表達(dá)式 用行內(nèi)否定句(if a is not b),不用肯定句的否定格式(if not a is b)。
不要通過(guò)長(zhǎng)度為0(if len(somelist) == 0)來(lái)檢查空的容器或序列(比如[]或者''),用if not somelist來(lái)假定空的列表為False
同理,if somelist隱式為T(mén)rue,對(duì)于非空的容器或序列([1]或者'hi')
-
多行表達(dá)式可以用括號(hào)和\來(lái)分隔
導(dǎo)入: 把import放在文件的最開(kāi)始(from x import y)
絕對(duì)路徑進(jìn)行導(dǎo)入,比如從包bar導(dǎo)入,應(yīng)該用from bar import foo,而不是import foo
如果一定要用相對(duì)路徑,則from . import foo
按照標(biāo)準(zhǔn)庫(kù),第三方庫(kù),自己的庫(kù)的順序來(lái)組織import語(yǔ)句,同級(jí)別的庫(kù)則按照字母順序排列。
使用Pylint等靜態(tài)分析器來(lái)輔助檢查PEP8風(fēng)格的代碼編寫(xiě)
- Item3:bytes和str的區(qū)別
a = b'h\x65llo'
print(list(a))
print(a)
>>>
[104, 101, 108, 108, 111]
b'hello'
b = 'a\u0300 propos'
print(list(b))
print(b)
>>>
['a', 'ˋ', ' ', 'p', 'r', 'o', 'p', 'o', 's']
a? propos
bytes沒(méi)有對(duì)應(yīng)的二進(jìn)制編碼,str沒(méi)有對(duì)應(yīng)的文本編碼。要轉(zhuǎn)換,需要通過(guò)str的encode方法或者bytes的decode方法。
統(tǒng)一編碼為UTF-8的str。
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode('utf-8')
else:
value = bytes_or_str
return value # Instance of str
print(repr(to_str(b'foo')))
print(repr(to_str('bar')))
>>>
'foo'
'bar'
- 統(tǒng)一為8-bits的bytes
def to_bytes(bytes_or_str):
if isinstance(bytes_or_str, str):
value = bytes_or_str.encode('utf-8')
else:
value = bytes_or_str
return value # Instance of bytes
print(repr(to_bytes(b'foo')))
print(repr(to_bytes('bar')))
>>>
b'foo'
b'bar'
- 同類型可以相加,不同類型不可以
print(b'one' + b'two')
print('one' + 'two')
>>>
b'onetwo'
onetwo
>>> b'one' + 'two'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat str to bytes
>>> 'one' + b'two'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not bytes
- 同理,同類型的可以進(jìn)行比較,不同則不可以
assert b'red' > b'blue'
assert 'red' > 'blue'
>>> assert 'red' > b'blue'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'str' and 'bytes'
>>> assert b'blue' < 'red'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'bytes' and 'str'
- 類型不同,比較永遠(yuǎn)為False,盡管文本內(nèi)容相同
print(b'foo' == 'foo')
>>>
False
- %操作符對(duì)于字符串格式的占位影響(同類型可以,不同類型則情況不同:1)把str放到bytes里面,由于不知道二進(jìn)制編碼方式,所以報(bào)錯(cuò);2)把bytes放到str里面,會(huì)把bytes以repr的調(diào)用結(jié)果放進(jìn)去)
print(b'red %s' % b'blue')
print('red %s' % 'blue')
>>>
b'red blue'
red blue
print(b'red %s' % 'blue')
>>>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not 'str'
print('red %s' % b'blue')
>>>
red b'blue'
- 寫(xiě)文件時(shí),注意寫(xiě)入的格式(帶b為傳入bytes,不帶則默認(rèn)為str)
with open('data.bin', 'wb') as f:
f.write(b'\xf1\xf2\xf3\xf4\xf5')
with open('data.bin', 'w') as f:
f.write(b'\xf1\xf2\xf3\xf4\xf5')
>>>
Traceback ...
TypeError: write() argument must be str, not bytes
- 讀文件時(shí),同理,如下:
with open('data.bin', 'r') as f:
data = f.read()
>>>
Traceback ...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 0: invalid continuation byte
with open('data.bin', 'rb') as f:
data = f.read()
assert data == b'\xf1\xf2\xf3\xf4\xf5'
- 查看默認(rèn)的平臺(tái)編碼,最好應(yīng)該顯式指定編碼的格式。(下面使用錯(cuò)誤的編碼格式,導(dǎo)致數(shù)據(jù)以另一種編碼方式來(lái)解讀;原本應(yīng)該使用b來(lái)解讀,這樣就不需要指定encoding的方式。)(進(jìn)一步可以使用help(open)來(lái)查看open這個(gè)函數(shù)的說(shuō)明。)
import locale
print(locale.getpreferredencoding())
>>>
cp936
with open('data.bin', 'r', encoding='cp1252') as f:
data = f.read()
assert data == '?òó??'
Item4:用F字符串,而不用C風(fēng)格的Format串和str.format
左邊用預(yù)定義的文本模板,右邊提供數(shù)值(比如用%d來(lái)解碼二進(jìn)制和十六進(jìn)制數(shù))
a = 0b10111011
b = 0xc5f
print('Binary is %d, hex is %d' % (a, b))
>>>
Binary is 187, hex is 3167
- Format串和str.format的各種例子(不足):
# 格式需要很好的指定,一旦指定錯(cuò)誤,就會(huì)報(bào)錯(cuò)
key = 'my_var'
value = 1.234
formatted = '%-10s = %.2f' % (key, value)
print(formatted)
>>>
my_var = 1.23
reordered_tuple = '%-10s = %.2f' % (value, key)
>>>
Traceback ...
TypeError: must be real number, not str
reordered_string = '%.2f = %-10s' % (key, value)
>>>
Traceback ...
TypeError: must be real number, not str
# 多個(gè)串的時(shí)候,可讀性和處理起來(lái)復(fù)雜
pantry = [
('avocados', 1.25),
('bananas', 2.5),
('cherries', 15),
]
for i, (item, count) in enumerate(pantry):
print('#%d: %-10s = %.2f' % (i, item, count))
>>>
#0: avocados = 1.25
#1: bananas = 2.50
#2: cherries = 15.00
# 當(dāng)修改樣式的時(shí)候,前后的格式需要對(duì)應(yīng),比如f對(duì)應(yīng)浮點(diǎn),d對(duì)應(yīng)整型
for i, (item, count) in enumerate(pantry):
print('#%d: %-10s = %d' % (
i + 1,
item.title(),
round(count)))
>>>
#1: Avocados = 1
#2: Bananas = 2
#3: Cherries = 15
# 這種斷層的代碼,可讀性較差,需要前后跳躍來(lái)閱讀,遇到bug也比較難找到。
template = '%s loves food. See %s cook.'
name = 'Max'
formatted = template % (name, name)
print(formatted)
>>>
Max loves food. See Max cook.
name = 'brad'
formatted = template % (name.title(), name.title())
print(formatted)
>>>
Brad loves food. See Brad cook.
# 通過(guò)字典來(lái)格式化,使得語(yǔ)句更加復(fù)雜。
key = 'my_var'
value = 1.234
old_way = '%-10s = %.2f' % (key, value)
new_way = '%(key)-10s = %(value).2f' % {
'key': key, 'value': value} # Original
reordered = '%(key)-10s = %(value).2f' % {
'value': value, 'key': key} # Swapped
assert old_way == new_way == reordered
name = 'Max'
template = '%s loves food. See %s cook.'
before = template % (name, name) # Tuple
template = '%(name)s loves food. See %(name)s cook.'
after = template % {'name': name} # Dictionary
assert before == after
for i, (item, count) in enumerate(pantry):
before = '#%d: %-10s = %d' % (
i + 1,
item.title(),
round(count))
after = '#%(loop)d: %(item)-10s = %(count)d' % {
'loop': i + 1,
'item': item.title(),
'count': round(count),
}
assert before == after
# 直接傳入字典,一定程度緩解了上面的問(wèn)題
soup = 'lentil'
formatted = 'Today\'s soup is %(soup)s.' % {'soup': soup}
print(formatted)
>>>
Today's soup is lentil.
menu = {
'soup': 'lentil',
'oyster': 'kumamoto',
'special': 'schnitzel',
}
template = ('Today\'s soup is %(soup)s, '
'buy one get two %(oyster)s oysters, '
'and our special entrée is %(special)s.')
formatted = template % menu
print(formatted)
>>>
Today's soup is lentil, buy one get two kumamoto oysters, and our special entrée is schnitzel.
# format則是指定格式,在簡(jiǎn)單語(yǔ)句上比較直觀。
a = 1234.5678
formatted = format(a, ',.2f') # 千分位以“,”分隔
print(formatted)
b = 'my string'
formatted = format(b, '^20s') # “^”指定居中的位數(shù)
print('*', formatted, '*')
>>>
1,234.57
* my string *
key = 'my_var'
value = 1.234
formatted = '{} = {}'.format(key, value)
print(formatted)
>>>
my_var = 1.234
formatted = '{:<10} = {:.2f}'.format(key, value)
print(formatted)
>>>
my_var = 1.23
print('%.2f%%' % 12.5)
print('{} replaces {{}}'.format(1.23))
>>>
12.50%
1.23 replaces {}
formatted = '{1} = {0}'.format(key, value)
print(formatted)
>>>
1.234 = my_var
formatted = '{0} loves food. See {0} cook.'.format(name)
print(formatted)
>>>
Max loves food. See Max cook.
# 但是一旦句式復(fù)雜,依然影響了可讀性。
for i, (item, count) in enumerate(pantry):
old_style = '#%d: %-10s = %d' % (
i + 1,
item.title(),
round(count))
new_style = '#{}: {:<10s} = {}'.format(
i + 1,
item.title(),
round(count))
assert old_style == new_style
#
formatted = 'First letter is {menu[oyster][0]!r}'.format(
menu=menu)
print(formatted)
>>>
First letter is 'k'
old_template = (
'Today\'s soup is %(soup)s, '
'buy one get two %(oyster)s oysters, '
'and our special entrée is %(special)s.')
old_formatted = template % {
'soup': 'lentil',
'oyster': 'kumamoto',
'special': 'schnitzel',
}
new_template = (
'Today\'s soup is {soup}, '
'buy one get two {oyster} oysters, '
'and our special entrée is {special}.')
new_formatted = new_template.format(
soup='lentil',
oyster='kumamoto',
special='schnitzel',
)
assert old_formatted == new_formatted
- 解釋的格式化串(interpolated format strings, f-strings)登場(chǎng)
key = 'my_var'
value = 1.234
formatted = f'{key} = {value}'
print(formatted)
>>>
my_var = 1.234
# 也可以用上前面的格式指定
formatted = f'{key!r:<10} = {value:.2f}'
print(formatted)
>>>
'my_var' = 1.23
# 各種方式的對(duì)比,f字符串簡(jiǎn)要(terseness),可讀性強(qiáng)。
f_string = f'{key:<10} = {value:.2f}'
c_tuple = '%-10s = %.2f' % (key, value)
str_args = '{:<10} = {:.2f}'.format(key, value)
str_kw = '{key:<10} = {value:.2f}'.format(key=key,
value=value)
c_dict = '%(key)-10s = %(value).2f' % {'key': key,
'value': value}
assert c_tuple == c_dict == f_string
assert str_args == str_kw == f_string
# 之前的例子改造為f串,顯然可讀性比前兩者要好。
for i, (item, count) in enumerate(pantry):
old_style = '#%d: %-10s = %d' % (
i + 1,
item.title(),
round(count))
new_style = '#{}: {:<10s} = {}'.format(
i + 1,
item.title(),
round(count))
f_string = f'#{i+1}: {item.title():<10s} = {round(count)}'
assert old_style == new_style == f_string
# 或者也可以拆分成多個(gè)f字符串,增強(qiáng)單行可讀性
for i, (item, count) in enumerate(pantry):
print(f'#{i+1}: '
f'{item.title():<10s} = '
f'{round(count)}')
>>>
#1: Avocados = 1
#2: Bananas = 2
#3: Cherries = 1
# 由于可以運(yùn)行表達(dá)式,指定的格式也可以以變量形式嵌入,而不用寫(xiě)死。
places = 3
number = 1.23456
print(f'My number is {number:.{places}f}')
>>>
My number is 1.235
以上是Item1到Item4的摘錄,主要以代碼例子為主。后續(xù)依然以代碼摘錄為主,體會(huì)pythonic的編寫(xiě)方式。