建議7.將常量集中到乙個檔案
python的內建命名空間是支援一小部分常量的,如true,false,none.只是python沒有提供定義常量的直接方式而已.那麼在python中應該如何使用常量呢?一般來說有以下兩種方法:
1.通過命名風格來提醒使用者該變數代表的意義為常量.如常量名所有字母大寫,用下劃線連線各個單詞,如max_overflow,total.而這種方式並沒有實現真正的常量,其對應的值仍然可以改變,這只是一種約定俗成的風格.
2.通過自定義的類實現常量功能.這要求符合」命名全部為大寫」和」值一旦繫結便不可再修改」這兩個條件.下面是一種較為常見的解決方法.它通過對常量對應的值進行修改時或者命名不符合規範時丟擲異常來滿足以上常量的兩個條件.
class
_const:
class
consterror
(typeerror):
pass
class
constcaseerror
(consterror):
pass
def__setattr__
(self, name, value):
if self.__dict__.has_key(name):
raise self.consterror,"can't change const.%s" % name
ifnot name.isupper():
raise self.constcaseerror, \
'const name "%s" is not all uppercase' % name
self.__dict__[name] = value
import sys
sys.modules[__name__]=_const()
如果上面的**對應的模組名為const,使用的時候只需要import const,便可以直接定義常量了.如一下**:
import
const
const.company = "ibm"
上面的**中常量一旦賦值便不可再更改,因此const.company=」sap」會丟擲const.consterror:異常,而常量名稱如果小寫,如const.name=」python」,也會丟擲const.constcaseerror異常.
無論採用哪一種方式來實現常量,都提倡將常量集中到乙個檔案中,因為這樣有利於維護,一旦需要修改常量的值,可以集中統一進行而不是逐個檔案去檢查.採用第二種方式實現的常量可以這麼做:將存放常量的檔案命名為constant.py,並在其中定義一系列常量.
class
_const:
class
consterror
(typeerror):
pass
class
constcaseerror
(consterror):
pass
def__setattr__
(self, name, value):
if self.__dict__.has_key(name):
raise self.consterror, "can't change const.%s" %name
ifnot name.isupper():
raise self.constcaseerror, \
"const name "%s" is not all uppercase" %name
self.__dict__[name] = value
import sys
sys.modules[__name__] = _const()
import const
const.my_constant = 1
const.my_second_constant = 2
const.my_third_constant = "a"
const.my_forth_constant = "b"
from constant import const
print const.my_second_constant
print const.my_third_constant*2
print const.my_forth_constant+"5"
建議8. 利用assert語句來發現問題.斷言(assert)在很多語言中都存在,它主要為除錯程式服務,能夠快速方便地檢查程式的異常或者發現不恰當的輸入等.可以防止意想不到的情況出現.
基本語法如下:
assert expression1 [",", expression2]
其中計算expression 1的值會返回true 或者 false,當值為false的時候會引發assertionerror, 而expression2是可選的,常用來傳遞具體的異常資訊.
來看乙個簡單的使用例子.
x = 1y = 2
assert x == y ,」not equals」
traceback (most recent call last):
file 「」,line 1, in
assertionerror: not equals
在執行過程中它實際相當於如下**:
x = 1y = 2
ifdebugand not x == y:
… raise assertionerror(「not equals」)
… traceback (most recent call last):
file 「」,line2,in
assertionerror:not equals
對python使用斷言需要說明如下:
1)debug的值預設設定為true,且是唯讀的,且在python2.7中還無法修改該值.
2) 斷言是有代價的,它會對效能產生一定的影響,對於編譯型的語言,如c/c++,這也許並不那麼重要.因為斷言只在除錯模式下啟用.但python並沒有嚴格定義除錯和發布模式之間的區別,通常禁用斷言的方法是在執行指令碼的時候加上-o標誌,這種方式帶來的影響是它並不優化位元組碼,而是忽略與斷言相關的語句.如:
def
foo(x):
assert x
foo(0)
執行python asserttest.py如下:
traceback (most recent call
last):
file "asserttest.py",line 4,in
foo(0)
file "asserttest.py",line 2,in foo
assert x
assertionerror
加上 -o的引數: python -o asserttest.py便可以禁用斷言.
斷言實際上是被設計用來捕獲使用者所定義的約束的,而不是用於捕獲程式本身錯誤的,因此使用斷言需要注意一下幾點:
1) 不要濫用,這是使用斷言最基本的原則.若是由於斷言引發了異常,通常代表程式中存在bug,因此斷言應該使用在正常邏輯不可到達的地方或正常情況下總是為真的場合.
2) 如果python本身的異常能夠處理就不要再使用斷言.如對於類似於陣列越界,型別不匹配,除數為0之類的錯誤,不建議使用斷言來進行處理.下面的例子中使用斷言就顯得多餘,因為如果傳入的引數乙個為字串,另乙個為數字或者列表,本身就會丟擲typeerror.
def stradd(x,y):… assert isinstance(x,basestring)
… assert isinstance(y,basestring)
… return x+y
3) 不要使用斷言來檢查使用者的輸入.最好用條件判斷.並在不符合條件的時候輸出錯誤提示資訊.
4) 在函式呼叫後,當需要確認返回值是否合理時,可以使用斷言.
5) 當條件是業務邏輯繼續下去的先決條件時可以使用斷言.如list1和其副本list2,業務繼續下去的條件是這兩個list必須是一樣的,但是由於某些不可控因素,如使用了淺拷貝而list1中含有可變物件等,就可以使用斷言來判斷這兩者的關係,如果不相等,則繼續執行後面的程式意義不大.
建議9: 數值交換值的時候不推薦使用中間變數.
x,y = y,x
這種方法更優一點,一般情況下,python表示式的計算順序是從左到右的,表示式賦值的時候表示式右邊的運算元先於左邊的運算元計算.因此表示式expr3,expr4 = expr1,expr2的計算順序是expr1,pxpr2->expr3, expr4.因此對於表示式x,y = y,x,其在記憶體中執行的順序如下:
1)先計算右邊的表示式y,x,因此先在記憶體中建立元祖(y,x),其識別符號和值分別是y,x及其對應的值.其中y和x是在初始化時已經存在與記憶體中的物件.
2)計算表示式左邊的值並進行賦值.元祖被依次分配給左邊的識別符號,通過解壓縮,元祖第乙個識別符號(為y)分配給左邊第乙個元素(此時為x),元祖第二個識別符號(為x)分配給第二個元素(此時為y),從而達到x,y值交換的目的.
摘選改善Python程式的91個建議2
62 metaclass stackflow 中文翻譯 63 python物件協議 65 python的迭代器協議 iter 可迭代物件 返回迭代器iterator 呼叫 呼叫一次返回乙個元素,當最後乙個元素返回後,再次呼叫時,丟擲stopiteration 異常 iterator.next 或 n...
改善python程式的91個建議讀書筆記1
引論 建議1 理解pythonic 的概念pythonic 也許可以遮陽定義 充分體現python 自身特色的 風格。python 中兩個變數交換只需一行 a,b b,a 遍歷乙個容器時可以為 for i in alist do sth with i 開啟檔案,需要安全的關閉檔案可以為 with o...
改善C 程式的157個建議(1)
2.使用預設轉型方法 3.區別對待強制轉型與as和is 1 避免裝箱 什麼是裝箱?指將乙個值型別隱式的轉換為object型別。裝箱為什麼會帶來效能損耗?因為它需要完成下面三個步驟 1 會為值型別在託管堆中分配記憶體。除了使用值型別本身所分配的記憶體空間外,記憶體總量還要加上型別物件指標和同步塊索引所...