Effective Python 筆記摘錄1

  • 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ě)方式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 第一部分 初識(shí)Python語(yǔ)言 第1章 程序設(shè)計(jì)基本方法 1.1 計(jì)算機(jī)的概念 計(jì)算機(jī)是根據(jù)指令操作數(shù)據(jù)的設(shè)備,具...
    不脫發(fā)的程序員閱讀 1,128評(píng)論 0 1
  • 作者 Zed A. Shaw 前言 要點(diǎn) 重視讀寫(xiě),注重細(xì)節(jié),發(fā)現(xiàn)不同 少瞅多問(wèn),親自動(dòng)手,刻意練習(xí),耐心實(shí)踐 學(xué)...
    Alex_0822閱讀 4,813評(píng)論 1 5
  • python===### 地址1. mac 下python 2.7的地址 /Library/Python/2.7/...
    Colaplusice閱讀 536評(píng)論 0 0
  • 本學(xué)習(xí)筆記針對(duì)有其他語(yǔ)言基礎(chǔ)的情況下記錄的, 主要記錄一些與其他語(yǔ)言不一樣的地方, 使用于快速學(xué)習(xí). 常用指令 p...
    GrayLand閱讀 1,070評(píng)論 0 3
  • 〇、前言 本文共108張圖,流量黨請(qǐng)慎重! 歷時(shí)1個(gè)半月,我把自己學(xué)習(xí)Python基礎(chǔ)知識(shí)的框架詳細(xì)梳理了一遍。 ...
    Raxxie閱讀 19,025評(píng)論 17 410