# -*- coding: utf-8 -*-
import os
# 第一章 用Pythonic方式來思考
#--------------------------------------
# 第1條:確認自己所使用的Python版本
# import this
#--------------------------------------
# 第2條:遵循PEP 8風格指南
# if not a is b 壞
# if a is not b 好
# if len(somelist) == 0 壞
# if not somelist 好
# 不要編寫單行的if語句、for循環、while循環、except複合語句
# import 放在文件開頭
# 引入模塊時,使用絕對名稱
# import語句分爲三個部分:標準庫模塊、第三方模塊、自用模塊,每部分中,按照模塊的字母順序排列
#--------------------------------------
# 第3條:瞭解bytes、str與unicode的區別
# Python3: bytes, str
# Python2: str, unicode
def to_unicode(unicode_or_str):
if isinstance(unicode_or_str, str):
value = unicode_or_str.decode("utf-8")
else:
value = unicode_or_str
return value # Instance of unicode
def to_str(unicode_or_str):
if isinstance(unicode_or_str, unicode):
value = unicode_or_str.encode("utf-8")
else:
value = unicode_or_str
return value # Instance of str
# 注:Python2 中,若str只包含7位ASCII字符,則unicode和str實例似乎就成了同一種類型
# 可以用+號連接這種str與unicode
# 可以用等價與不都能加操作符
# 可以用'%s'等形式來代表unicode實例
with open("random.bin", "w") as f:
f.write(os.urandom(10))
#--------------------------------------
# 第4條:用輔助函數來取代複雜的表達式
def get_first_int(values, key, default=0):
found = values.get(key, [""])
if found[0]:
found = int(found[0])
else:
found = default
return found
#--------------------------------------
# 第5條:瞭解切割序列的辦法
a = [1,2,3]
b = a[:]
assert b == a and b is not a # 原列表的拷貝
b = a
print "Before {}".format(a)
a[:] = [101, 102, 103]
assert a is b # Still the same list object
print "After {}".format(a) # Now has different contents
#--------------------------------------
# 第6條:在單次切片操作內,不要同時指定start、end和stride
a = ["red", "orange", "yellow", "green", "blue", "purple"]
odds = a[::2]
evens = a[1::2]
print odds
print evens
x = "mongoose" # 翻轉字符串,對字符串和ASCII字符有用,
y = x[::-1]
print y
w = u"謝謝" # 但對於已經編碼成UTF-8字符串的Unicode字符無效
x = w.encode("utf-8")
y = x[::-1]
# z = y.decode("utf-8") # UnicodeDecodeError
a = ["a", "b", "c", "d", "e", "f", "g", "h"] # 拆解爲兩條賦值語句,一條範圍切割,一條步進操作
b = a[::2]
c = b[1:-1]
print c
#--------------------------------------
# 第7條:用列表推到來取代map和filter(更清晰,無需編寫lambda表達式)
a = [1,2,3,4,5,6,7,8,9,10]
squares = [x**2 for x in a]
print squares
squares = map(lambda x: x**2, a)
even_squares = [x**2 for x in a if x % 2 == 0]
print even_squares
alt = map(lambda x: x**2, filter(lambda x: x % 2 == 0, a))
assert even_squares == list(alt)
# dict和set也有列表類似的推到機制
chile_ranks = {"ghost": 1, "habanero": 2, "cayenne": 3}
rank_dict = {rank: name for name, rank in chile_ranks.iteritems()}
print rank_dict
chile_len_set = {len(name) for name in rank_dict.itervalues()}
print chile_len_set
# {1: 'ghost', 2: 'habanero', 3: 'cayenne'}
# set([8, 5, 7])
#--------------------------------------
# 第8條:不要使用含有兩個以上表達式的列表推導
# 可以使用兩個條件、兩個循環、或一個條件搭配一個循環
matrix = [[1,2,3],[4,5,6],[7,8,9]]
flat = [x for row in matrix for x in row] # 多重循環的用法
print flat
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
squared = [[x**2 for x in row] for row in matrix] # 多重循環的用法
print squared
a = [1,2,3,4,5,6,7,8,9,10]
b = [x for x in a if x > 4 if x % 2 == 0]
c = [x for x in a if x > 4 and x % 2 == 0]
print b
assert b == c
matrix = [[1,2,3],[4,5,6],[7,8,9]]
filtered = [[x for x in row if x % 3 == 0] # 晦澀難懂
for row in matrix if sum(row) >= 10]
print filtered
#--------------------------------------
# 第9條:用生成器表達式來改寫數據量較大的列表推導
value = [len(x) for x in open("hello.txt")]
print value
it = (len(x) for x in open("hello.txt")) # 返回一個生成器
print it
print next(it) # 獲取下一個值,不用擔心內存激增
print next(it)
# 生成器表達式可以相互組合
# 外圍的迭代器每次前進時,會推動內部的迭代器,產生連鎖效應
# 使得執行循環、評估條件表達式、對接輸入和輸出等邏輯都組合在了一起
roots = ((x, x**0.5) for x in it)
print next(roots)
#--------------------------------------
# 第10條:儘量用enumerate取代range
# enumerate將各種迭代器包裝爲生成器,以便稍後產生輸出值
fruit_list = ["apple", "banana", "orange"]
# for i in range(len(fruit_list)):
# print "%d: %s" % (i+1, fruit_list[i])
for i, fruit in enumerate(fruit_list): # 簡潔、清爽
print "%d: %s" % (i+1, fruit)
#--------------------------------------
# 第11條:用zip函數同時遍歷兩個迭代器
# 例子,獲取列表中最長字符串
names = ["Lebron", "Bryant", "Wade", "HongfeiXu"]
letters = [len(n) for n in names]
longest_name = None
max_letters = 0
for i in range(len(names)): # 同時遍歷兩個列表看起來很混亂
count = letters[i]
if count > max_letters:
longest_name = names[i]
max_letters = count
print longest_name
longest_name = None
max_letters = 0
for name, count in zip(names, letters): # 清爽很多
if count > max_letters:
longest_name = name
max_letters = count
print longest_name
# 注1:Python2中zip並不是生成器,會將提供的迭代器全部平行的遍歷一次,將完整的遠足列表返回給調用者,可能會帶來內存劇增
# 如果要遍歷數據量較大的迭代器,應該使用itertools內置模塊中的izip,見第46條
# 注2:如果輸入的迭代器長度不同,則當一個耗盡,zip就不再產生元組了
# 如果不能確定zip所封裝的列表是否等長,則可考慮使用itertools中的zip_longest函數,Python2中叫做izip_longest
#--------------------------------------
# 第12條:不要在for和while循環後面寫else塊
a = 4
b = 9
for i in range(2, min(a, b) + 1):
print "Testing %d" % i
if a % 2 == 0 and b % i == 0:
print "Not coprime"
break
else:
print "Coprime"
def coprime(a, b):
for i in range(2, min(a, b) + 1):
if a % 2 == 0 and b % i == 0:
return False
return True
#--------------------------------------
# 第13條:合理利用try/except/else/finally結構中的每個代碼塊
# 1. finally塊
# 既要將異常向上傳播,又要在異常發生時執行清理工作,則使用try/finally結構
# 常見用途,確保程序能夠可靠地關閉文件句柄
handle = open("hello.txt") # May raise IOError
try:
data = handle.read() # May rasie UnicodeDecodeError
finally:
handle.close() # Always runs after try:
# 2. else塊
# try/except/else結構可以清晰地描述出哪些異常會由自己的代碼來處理、哪些異常會傳播到上一級
# 如果try沒有發生異常,那麼就執行else塊
# else塊可以儘量縮減try塊內的代碼量
import json
def load_json_key(data, key):
try:
result_dict = json.loads(data) # May raise ValueError
except ValueError as e: # 捕獲處理 ValueError
raise KeyError(e)
else:
return result_dict[key] # May raise KeyError,若有異常,則向上傳播
# 3. 混合使用
UNDEFINE = object()
def divide_json(path):
handle = open(path, "r+") # May raise IOError
try:
data = handle.read() # May raise UnicodeDecodeError
op = json.loads(data) # May raise ValueError
value = (
op["numerator"]/
op["denominator"]) # May raise ZeroDivisionError
except ZeroDivisionError as e:
return UNDEFINE
else:
op["result"] = value
result = json.dumps(op)
handle.seek(0)
handle.write(result) # May raise IOError
return value
finally:
handle.close() # Always runs
[Effective Python] 第1章 用Pythonic方式來思考
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.