網站性能檢測評分
注:本網站頁面html檢測工具掃描網站中存在的基本問題,僅供參考。
python中type
在Python 2.7即將停止支持時,我們?yōu)槟銣蕚淞艘环?.x遷移指南 營銷視頻課程
機器之心編譯
目前,Python 科學棧中的所有主要項目都同時支持 Python 3.x 和 Python 2.7,不過,這種情況很快即將結束。去年 11 月,Numpy 團隊的一份聲明引發(fā)了數據科學社區(qū)的關注:這一科學計算庫即將放棄對于 Python 2.7 的支持,全面轉向 Python 3。Numpy 并不是唯一宣稱即將放棄 Python 舊版本支持的工具,pandas 與 Jupyter notebook 等很多產品也在即將放棄支持的名單之中。對于數據科學開發(fā)者而言,如何將已有項目從 Python 2 轉向 Python 3 成為了正在面臨的重大問題。來自莫斯科大學的 Alex Rogozhnikov 博士為我們整理了一份代碼遷移指南。
Python 3 功能簡介
Python 是機器學習和其他科學領域中的主流語言,我們通常需要使用它處理大量的數據。Python 兼容多種深度學習框架,且具備很多優(yōu)秀的工具來執(zhí)行數據預處理和可視化。
但是,Python 2 和 Python 3 長期共存于 Python 生態(tài)系統(tǒng)中,很多數據科學家仍然使用 Python 2。2019 年底,Numpy 等很多科學計算工具都將停止支持 Python 2,而 2018 年后 Numpy 的所有新功能版本將只支持 Python 3。
為了使 Python 2 向 Python 3 的轉換更加輕松,我收集了一些 Python 3 的功能,希望對大家有用。
使用 pathlib 更好地處理路徑
pathlib 是 Python 3 的默認模塊,幫助避免使用大量的 os.path.joins:
from pathlib importPath
dataset ='wiki_images'
datasets_root =Path('/path/to/datasets/')
train_path = datasets_root / dataset /'train'
test_path = datasets_root / dataset /'test'
for image_path in train_path.iterdir():
with image_path.open()as f:# note, open is a method of Path object
# do something with an image
Python 2 總是試圖使用字符串級聯(準確,但不好),現在有了 pathlib,代碼安全、準確、可讀性強。
此外,pathlib.Path 具備大量方法,這樣 Python 新用戶就不用每個方法都去搜索了:
p.exists()
p.is_dir()
p.parts()
p.with_name('sibling.png')# only change the name, but keep the folder
p.with_suffix('.jpg')# only change the extension, but keep the folder and the name
p.chmod(mode)
p.rmdir()
pathlib 會節(jié)約大量時間,詳見:
文檔:https://docs.python.org/3/library/pathlib.html;
參考信息:https://pymotw/3/pathlib/。
類型提示(Type hinting)成為語言的一部分
PyCharm 中的類型提示示例:
Python 不只是適合腳本的語言,現在的數據流程還包括大量步驟,每一步都包括不同的框架(有時也包括不同的邏輯)。
類型提示被引入 Python,以幫助處理越來越復雜的項目,使機器可以更好地進行代碼驗證。而之前需要不同的模塊使用自定義方式在文檔字符串中指定類型(注意:PyCharm 可以將舊的文檔字符串轉換成新的類型提示)。
下列代碼是一個簡單示例,可以處理不同類型的數據(這就是我們喜歡 Python 數據棧之處)。
def repeat_each_entry(data):
""" Each entry in the data is doubled
"""
index = numpy.repeat(numpy.arange(len(data)),2)
return data[index]
上述代碼適用于 numpy.array(包括多維)、astropy.Table 和 astropy.Column、bcolz、cupy、mxnet.ndarray 等。
該代碼同樣可用于 pandas.Series,但是方式是錯誤的:
repeat_each_entry(pandas.Series(data=[0,1,2], index=[3,4,5]))# returns Series with Nones inside
這是一個兩行代碼。想象一下復雜系統(tǒng)的行為多么難預測,有時一個函數就可能導致錯誤的行為。明確了解哪些類型方法適合大型系統(tǒng)很有幫助,它會在函數未得到此類參數時給出提醒。
def repeat_each_entry(data:Union[numpy.ndarray, bcolz.carray]):
如果你有一個很棒的代碼庫,類型提示工具如 MyPy 可能成為集成流程中的一部分。不幸的是,提示沒有強大到足以為 ndarrays/tensors 提供細粒度類型,但是或許我們很快就可以擁有這樣的提示工具了,這將是 DS 的偉大功能。
類型提示 → 運行時的類型檢查
默認情況下,函數注釋不會影響代碼的運行,不過它也只能幫你指出代碼的意圖。
但是,你可以在運行時中使用 enforce 等工具強制進行類型檢查,這可以幫助你調試代碼(很多情況下類型提示不起作用)。
@enforce.runtime_validation
def foo(text: str)->None:
print(text)
foo('Hi')# ok
foo(5)# fails
@enforce.runtime_validation
def any2(x:List[bool])->bool:
return any(x)
any ([False,False,True,False])# True
any2([False,False,True,False])# True
any (['False'])# True
any2(['False'])# fails
any ([False,None,"",0])# False
any2([False,None,"",0])# fails
函數注釋的其他用處
如前所述,注釋不會影響代碼執(zhí)行,而且會提供一些元信息,你可以隨意使用。
例如,計量單位是科學界的一個普遍難題,astropy 包提供一個簡單的裝飾器(Decorator)來控制輸入量的計量單位,并將輸出轉換成所需單位。
# Python 3
from astropy import units as u
@u.quantity_input()
def frequency(speed: u.meter / u.s, wavelength: u.m)->u.terahertz:
return speed / wavelength
frequency(speed=300_000 * u.km / u.s, wavelength=555* u.nm)
# output: 540.5405405405404 THz, frequency of green visible light
如果你擁有 Python 表格式科學數據(不必要太多),你應該嘗試一下 astropy。你還可以定義針對某個應用的裝飾器,用同樣的方式來控制/轉換輸入和輸出。
通過 @ 實現矩陣乘法
下面,我們實現一個最簡單的機器學習模型,即帶 L2 正則化的線性回歸:
# l2-regularized linear regression: || AX - b ||^2 + alpha * ||x||^2 ->min
# Python 2
X = np.linalg.inv(np.dot(A.T, A)+ alpha * np.eye(A.shape[1])).dot(A.T.dot(b))
# Python 3
X = np.linalg.inv(A.T @ A + alpha * np.eye(A.shape[1]))@(A.T @ b)
下面 Python 3 帶有 @ 作為矩陣乘法的符號更具有可讀性,且更容易在深度學習框架中轉譯:因為一些如 X @ W + b[None, :] 的代碼在 numpy、cupy、pytorch 和 tensorflow 等不同庫下都表示單層感知機。
使用 ** 作為通配符
遞歸文件夾的通配符在 Python2 中并不是很方便,因此才存在定制的 glob2 模塊來克服這個問題。遞歸 flag 在 Python 3.6 中得到了支持。
import glob
# Python 2
found_images = \
glob.glob('/path*.jpg') \
+ glob.glob('/path*.jpg') \
+ glob.glob('/path***.jpg')
# Python 3
found_images = glob.glob('/path*.jpg', recursive=True)
python3 中更好的選擇是使用 pathlib:
# Python 3
found_images = pathlib.Path('/path/').glob('**/*.jpg')
Print 在 Python3 中是函數
Python 3 中使用 Print 需要加上麻煩的圓括弧,但它還是有一些優(yōu)點。
使用文件描述符的簡單句法:
print>>sys.stderr,"critical error"# Python 2
print("critical error", file=sys.stderr)# Python 3
在不使用 str.join 下輸出 tab-aligned 表格:
# Python 3
print(*array, sep='\t')
print(batch, epoch, loss, accuracy, time, sep='\t')
修改與重新定義 print 函數的輸出:
# Python 3
_print =print# store the original print function
defprint(*args,**kargs):
pass# do something useful, e.g. store output to some file
在 Jupyter 中,非常好的一點是記錄每一個輸出到獨立的文檔,并在出現錯誤的時候追蹤出現問題的文檔,所以我們現在可以重寫 print 函數了。
在下面的代碼中,我們可以使用上下文管理器暫時重寫 print 函數的行為:
@contextlib.contextmanager
def replace_print():
import builtins
_print =print# saving old print function
# or use some other function here
builtins.print=lambda*args,**kwargs: _print('new printing',*args,**kwargs)
yield
builtins.print= _print
with replace_print():
上面并不是一個推薦的方法,因為它會引起系統(tǒng)的不穩(wěn)定。
print 函數可以加入列表解析和其它語言構建結構。
# Python 3
result = process(x)if is_valid(x)elseprint('invalid item: ', x)
f-strings 可作為簡單和可靠的格式化
默認的格式化系統(tǒng)提供了一些靈活性,且在數據實驗中不是必須的。但這樣的代碼對于任何修改要么太冗長,要么就會變得很零碎。而代表性的數據科學需要以固定的格式迭代地輸出一些日志信息,通常需要使用的代碼如下:
# Python 2
print('{batch:3} {epoch:3} / {total_epochs:3} accuracy: {acc_mean:0.4f}±{acc_std:0.4f} time: {avg_time:3.2f}'.format(
batch=batch, epoch=epoch, total_epochs=total_epochs,
acc_mean=numpy.mean(accuracies), acc_std=numpy.std(accuracies),
avg_time=time / len(data_batch)
))
# Python 2 (too error-prone during fast modifications, please avoid):
print('{:3} {:3} / {:3} accuracy: {:0.4f}±{:0.4f} time: {:3.2f}'.format(
batch, epoch, total_epochs, numpy.mean(accuracies), numpy.std(accuracies),
time / len(data_batch)
))
樣本輸出:
12012/300 accuracy:0.8180±0.4649 time:56.60
f-strings 即格式化字符串在 Python 3.6 中被引入:
# Python 3.6+
print(f'{batch:3} {epoch:3} / {total_epochs:3} accuracy: {numpy.mean(accuracies):0.4f}±{numpy.std(accuracies):0.4f} time: {time / len(data_batch):3.2f}')
另外,寫查詢語句時非常方便:
query = f"INSERT INTO STATION VALUES (13, '{city}', '{state}', {latitude}, {longitude})"
「true pision」和「integer pision」之間的明顯區(qū)別
對于數據科學來說這種改變帶來了便利(但我相信對于系統(tǒng)編程來說不是)。
data = pandas.read_csv('timing.csv')
velocity = data['distance']/ data['time']
Python 2 中的結果依賴于『時間』和『距離』(例如,以米和秒為單位)是否被保存為整數。
在 Python 3 中,結果的表示都是精確的,因為除法的結果是浮點數。
另一個案例是整數除法,現在已經作為明確的運算:
n_gifts = money // gift_price # correct for int and float arguments
注意,該運算可以應用到內建類型和由數據包(例如,numpy 或 pandas)提供的自定義類型。
嚴格排序
# All these comparisons are illegal in Python 3
3<'3'
2 (3,4)<(3,None) (4,5)<[4,5] # False in both Python 2 and Python 3 (4,5)==[4,5] 防止不同類型實例的偶然性的排序。 sorted([2,'1',3])# invalid for Python 3, in Python 2 returns [2, 3, '1'] 在處理原始數據時幫助發(fā)現存在的問題。 旁注:對 None 的合適檢查是(兩個版本的 Python 都適用): if a isnotNone: pass if a:# WRONG check for None pass 自然語言處理的 Unicode s ='您好' print(len(s)) print(s[:2]) 輸出: Python 2: 6\n Python 3: 2\n 您好. x = u'со' x +='co'# ok x +='со'# fail Python 2 在此失敗了,而 Python 3 可以如期工作(因為我在字符串中使用了俄文字母)。 在 Python 3 中 strs 是 Unicode 字符串,對非英語文本的 NLP 處理更加方便。 還有其它有趣的方面,例如: 'a'< type < u'a'# Python 2: True 'a'< u'a'# Python 2: False from collections importCounter Counter('Mbelstück') Python 2: Counter({'\xc3': 2, 'b': 1, 'e': 1, 'c': 1, 'k': 1, 'M': 1, 'l': 1, 's': 1, 't': 1, '\xb6': 1, '\xbc': 1}) Python 3: Counter({'M': 1, '': 1, 'b': 1, 'e': 1, 'l': 1, 's': 1, 't': 1, 'ü': 1, 'c': 1, 'k': 1}) 這些在 Python 2 里也能正確地工作,但 Python 3 更為友好。 保留詞典和**kwargs 的順序 在 CPython 3.6+ 版本中,字典的默認行為類似于 OrderedDict(在 3.7+版本中已得到保證)。這在字典理解(和其他操作如 json 序列化/反序列化期間)保持順序。 import json x ={str(i):i for i in range(5)} json.loads(json.dumps(x)) # Python 2 {u'1':1, u'0':0, u'3':3, u'2':2, u'4':4} # Python 3 {'0':0,'1':1,'2':2,'3':3,'4':4} 它同樣適用于**kwargs(在 Python 3.6+版本中):它們的順序就像參數中顯示的那樣。當設計數據流程時,順序至關重要,以前,我們必須以這樣繁瑣的方式來編寫: from torch import nn # Python 2 model = nn.Sequential(OrderedDict([ ('conv1', nn.Conv2d(1,20,5)), ('relu1', nn.ReLU()), ('conv2', nn.Conv2d(20,64,5)), ('relu2', nn.ReLU()) ])) # Python 3.6+, how it *can* be done, not supported right now in pytorch model = nn.Sequential( conv1=nn.Conv2d(1,20,5), relu1=nn.ReLU(), conv2=nn.Conv2d(20,64,5), relu2=nn.ReLU()) ) 注意到了嗎?名稱的唯一性也會被自動檢查。 迭代地拆封 # handy when amount of additional stored info may vary between experiments, but the same code can be used in all cases model_paramteres, optimizer_parameters,*other_params = load(checkpoint_name) # picking two last values from a sequence *prev, next_to_last, last = values_history # This also works with any iterables, so if you have a function that yields e.g. qualities, # below is a simple way to take only last two values from a list *prev, next_to_last, last = iter_train(args) 默認的 pickle 引擎為數組提供更好的壓縮 # Python 2 import cPickle as pickle import numpy print len(pickle.dumps(numpy.random.normal(size=[1000,1000]))) # result: 23691675 # Python 3 import pickle import numpy len(pickle.dumps(numpy.random.normal(size=[1000,1000]))) # result: 8000162 節(jié)省 3 倍空間,而且速度更快。實際上,類似的壓縮(不過與速度無關)可以通過 protocol=2 參數來實現,但是用戶?...
JS中的typeof和類型判斷 互聯網視頻課程
typeof
ECMAScript 有 5 種原始類型(primitive type),即 Undefined、Null、Boolean、Number 和 String。我們都知道可以使用typeof運算符求得一個變量的類型,但是對引用類型變量卻只會返回object,也就是說typeof只能正確識別基本類型值變量。
var a = "abc";typeof a;// "string"var b = 123;typeof b;// "number"var c = true;typeof c;// "boolean"var d = null;typeof d;// "object"var f = undefined;typeof f;// "undefined"var g;typeof g;// "undefined"typeof x;// "object"
您也許會問,為什么 typeof 運算符對于 null 值會返回 "object"。這實際上是 JavaScript 最初實現中的一個錯誤,然后被 ECMAScript 沿用了?,F在,null 被認為是對象的占位符,從而解釋了這一矛盾,但從技術上來說,它仍然是原始值。
最后一個比較奇怪,typeof一個不存在的變量x居然返回了"object"而不是"undefined"。
我們在來如下代碼
var a = function() {};typeof a; // "function"var b = [1,2,3];typeof b; // "object"var c = {};typeof c; // "object"
對于數組和對象都返回"object",因此我們日常開發(fā)中一個常見需求就是如何判斷變量是數組還是對象。
類型判斷
類型判斷,一般就是判斷是否是數組,是否是空對象。這是針對這個需求,我日常用過或見過的判斷方法
判斷是否是數組
有數組:var a = [1,2,3,4,5];
方法一:
toString.call(a); // "[object Array]"
方法二:
a instanceof Array; //true
方法三:
a.constructor == Array; //true
第一種方法比較通用,也就是Object.prototype.toString.call(a)的簡寫。
instanceof和constructor判斷的變量,必須在當前頁面聲明的,比如,一個頁面(父頁面)有一個框架,框架中引用了一個頁面(子頁面),在子頁面中聲明了一個a,并將其賦值給父頁面的一個變量,這時判斷該變量,Array == object.constructor會返回false;
判斷是否是空對象
有變量:var obj = {};
JSON.stringify(obj); // "{}"
通過轉換成JSON對象來判斷是否是空大括號
if(obj.id){ //如果屬性id存在....}
這個方法比較土,大多數人都能想到,前提是得知道對象中有某個屬性。
function isEmptyObject(e) { var t; for (t in e) return !1; return !0 } //trueisEmptyObject(obj); //falseisEmptyObject({ "a":1, "b":2});
這個方法是jQuery的isEmptyObject()方法的實現方式。
┏━━━━━━━━━━━━┓
┃打出“php”
┃選第一個
┃發(fā)到評論
┃看看你打出來的是什么
┗━━━━━━━━━━━━
Python中集合(set)類型的詳細解釋及操作 公司視頻課程
一、集合(set)類型的含義:
Set是一個無序不重復元素集,與列表和元組不同,集合是無序的,無法通過數字進行索引。
注意:下面所舉例子在python3.6,IDE為pycharm2016.1中通過。
創(chuàng)建集合:用set()函數,或直接賦值。
例子:
x=set('Nike MM')
y=set(['w','a','m','a'])
print(x)
print(y)
輸出:
{'M', 'N', 'e', 'k', ' ', 'i'}
{'w', 'm', 'a'}
可以看到,在輸出中,是用一對{}號包住,里面重復的元素被去除。
再看一個例子:
s={'11','22','33'}
print(s)
print(type(s))
s={}
{'33', '11', '22'}
在定義不,不能用s={},這關創(chuàng)建的實際上是一個字典類型。
二、有關集合的操作:
1.增加操作
a=set('python')
a.add('why')
print(a)
b=set('python')
b.update('why')
print(b)
{'n', 'p', 'y', 'h', 'o', 't', 'why'}
{'n', 'p', 'y', 'h', 'o', 'w', 't'}
可能看到:add是單個元素的添加,并沒有把元素再分拆為單個字符。Update是批量的增加,增加的元素如果是一個字符串(實際上,在Python中字符串也是一個系列),是作為一個系列增加的。在輸出結果中,兩個函數都是無序的,并且無重復,也非添加到尾部。
2.刪除操作(remove,discard,pop)
例子1:
a=set('abcdefghijk')
a.remove('a')
a.remove('w')
輸出 :
Traceback (most recent call last):
{'h', 'k', 'e', 'd', 'g', 'c', 'f', 'i', 'b', 'j'}
File "D:/python/temp3.py", line 4, in
KeyError: 'w'
例子2:
a.discard('a')
a.discard('w')
{'f', 'h', 'd', 'e', 'b', 'k', 'i', 'j', 'c', 'g'}
例子3:
b=a.pop()
print(b,type(b))
{'k', 'd', 'h', 'c', 'b', 'j', 'g', 'i', 'e', 'f'}
a
從以上例子可以看到,remove方法刪除指定無素,如果要刪除的元素的不在集合中,則報錯;discard方法刪除指定元素,如果要刪除物元素不在集合中,則不報錯,pop方法刪除任意元素,并可將這個元素賦值給一個變量,但集合并沒有把這個元素移除。
3.清空(clear)
例子:
a.clear()
set()
4.交集&,并集|,差集-,對稱差集^,子集(被包含)<=,父集(包含)>=
a=set(['a','b','c','d','e','f'])
b=set(('d','e','f','g','h','i'))
d=set('def')
print('交集:',a.intersection(b))
print('交集:',a & b)
print('并集:',a.union(b))
print('并集:',a | b)
print('差集:',a.difference(b))
print('差集:',a-b)
#對稱差集:
#把兩個集合中相同的元素去掉,然后
#兩個集合中剩下的元素組成一個新的集合
print('對稱差集:',a.symmetric_difference(b) )
print('對稱差集:',a ^ b )
print('子集:',a.issubset(d) )
print('子集:',a<=d )
print('父集:',a.issuperset(d) )
print('父集:',a>=d )
交集: {'f', 'e', 'd'}
并集: {'c', 'e', 'd', 'b', 'f', 'a', 'g', 'i', 'h'}
差集: {'a', 'c', 'b'}
對稱差集: {'a', 'c', 'g', 'b', 'i', 'h'}
子集: False
父集: True
5.集合的其它一些操作
#如果a和d沒有交集,返回True,有則返回False
print(a.isdisjoint(d) ) 輸出:False
print(a print(a>d) 輸出:True print(a!=b) 輸出:True print(a.copy()) 輸出:{'f', 'e', 'b', 'a', 'd', 'c'} #復制一個集合 print('a' in a) 輸出:True #測試元素是否在集合中 print('a' not in a) 輸出:False #測試元素是否不在集合中 print(len(a)) 輸出:6 #返回集合的長度 6.集合計算: (1) #從a中減去a和b的交集,即從a集合中刪除和b集合中相同的元素 a.difference_update(b) 即等于:a=a-b 或a-=b print(a) 輸出:{'a', 'b', 'c'} (2) #修改a集合,僅僅保持a與b的交集,如果沒有交集,則a變?yōu)榭占蟬et() a.intersection_update(b) 即等于:a=a&b 或a&=b print(a ) 輸出:{'e', 'd', 'f'} (3) #a集合中增加‘在b集合中除去a和b交集剩下的元素’ a.symmetric_difference_update(b) 即等于:a=a^b 或 a^=b print(a) 輸出:{'i', 'g', 'a', 'c', 'b', 'h'}
Python代碼風格:PEP8規(guī)則 筆記 行業(yè)視頻課程
Python程序設計的代碼風格應該遵循PEP8規(guī)則:
一、代碼布局
1、縮進:
每級縮進4個空格(不用Tab,更不空格Tab混用)
1、續(xù)行應該與其包裹元素對齊,要么使用圓括號、方括號和花括號內的隱式行連接來垂直對齊,要么使用懸掛式縮進對齊。當使用懸掛縮進時,應該考慮到第一行不應該有參數,以及使用縮進以區(qū)分自己是續(xù)行。
2、縮進4個空格的規(guī)則對于續(xù)行是可選的。
3、當 if 語句的條件部分長到需要換行寫的時候,注意可以在兩個字符關鍵字的連接處(比如 if ),增加一個空格,再增加一個左括號來創(chuàng)造一個4空格縮進的多行條件。這會與 if 語句內同樣使用4空格縮進的代碼產生視覺沖突。PEP沒有明確指明要如何區(qū)分i發(fā)的條件代碼和內嵌代碼??墒褂玫倪x項包括但不限于下面幾種情況:
4、(可以參考下面關于是否在二進制運算符之前或之后截斷的討論)
在多行結構中的大括號/中括號/小括號的右括號可以與內容對齊單獨起一行作為最后一行的第一個字符,如:
或者也可以與多行結構的第一行第一個字符對齊,如:
2、Tab還是空格?
空格是被首先推薦的縮進方式。
Tab應該只在現有代碼已經使用tab進行縮進的情況下使用,以便和現有代碼保持一致。
Python 3不允許再同一個代碼塊中Tab和空格混合使用。
混合使用制表符和空格縮進的Python2代碼應該統(tǒng)一轉成空格。
使用命令行運行Python 2時,使用-t選項,會出現非法混用tab和空格的警告。當使用-tt選項時,這些警告會變成錯誤。強烈推薦使用這些選項!
3、最大行長
每行最大長度79個字符。
對于連續(xù)大段的文字(比如文檔字符串(docstring)或注釋),每行應該被限制在72個字符長度內。
Python標準庫比較傳統(tǒng),將行長限制在79個字符以內(文檔字符串/注釋為72個字符)。
一種推薦的換行方式是利用Python圓括號、方括號和花括號中的隱式續(xù)行。長行可以通過在括號內換行來分成多行。應該最好加上反斜杠來區(qū)別續(xù)行。
有時續(xù)行只能使用反斜杠才。例如,較長的多個 with 語句不能采用隱式續(xù)行,只能接受反斜杠表示換行:
另一個這樣的例子是assert語句。要確保續(xù)行的縮進適當。
在二元運算符之前應該換行嗎?
遵循數學的傳統(tǒng)能產出更多可讀性高的代碼:
4、空行
頂層函數和類的定義,前后用兩個空行隔開。
類里的方法定義用一個空行隔開。
相關的功能組可以用額外的空行(盡量少地)隔開。一堆相關的單行代碼之間的空白行可以省略(例如,一組虛擬實現 dummy implementations)。
在函數中使用空行來區(qū)分邏輯段(盡量少地)。
Python接受control-L(即^L)換頁符作為空格;許多工具把這些字符當作頁面分隔符,所以你可以在文件中使用它們來分隔相關段落。請注意,一些編輯器和基于Web的代碼閱讀器可能無法識別control-L為換頁,將在其位置顯示另一個字形。
5、源文件編碼
Python核心發(fā)布版本中的代碼總是以UTF-8格式編碼(或者在Python2中用ASCII編碼)。
使用ASCII(Python 2)或者UTF-8(Python 3)的文件不應該添加編碼聲明。
在標準庫中,只有用作測試目的,或者注釋或文檔字符串需要提及作者名字而不得不使用非ASCII字符時,才能使用非默認的編碼。否則,在字符串文字中包括非ASCII數據時,推薦使用\x, \u, U或N等轉義符。
對于Python 3.0及其以后的版本中,標準庫遵循以下原則(參見PEP 3131):Python標準庫中的所有標識符都必須只采用ASCII編碼的標識符,在可行的條件下也應當使用英文詞(很多情況下,使用的縮寫和技術術語詞都不是英文)。此外,字符串文字和注釋應該只包括ASCII編碼。只有兩種例外:
(a) 測試情況下為了測試非ASCII編碼的特性
(b) 作者名字。作者名字不是由拉丁字母組成的也必須提供一個拉丁音譯名。
鼓勵面向全球的開源項目都采用類似的原則。
6、導入
1、imports應該分行寫,而不是都寫在一行,例如:
這樣寫也是可以的:
導入(import)始終在文件的頂部,在模塊注釋和文檔字符串之后,在模塊全局變量和常量之前。
導入順序如下:
imports應該按照下面的順序分組來寫:
1、標準庫imports
2、相關第三方imports
3、本地應用/庫的特定imports
不同組的imports之前用空格隔開。
將任何相關的 __all__ 說明(specification)放在imports之后。
推薦使用絕對(absolute)imports,因為這樣通常更易讀,在import系統(tǒng)沒有正確配置的情況下,也會有更好的表現(或者至少會給出錯誤信息):
在絕對路徑比較長的情況下,也可以使用相對導入:
Python 3中已經禁止隱式的相對導入。
導入類的方法,通??梢赃@樣寫:
如果和本地命名的拼寫產生了沖突,應當使用絕對導入:
禁止使用通配符導入。
通配符導入(from import *)應該避免,因為它不清楚命名空間有哪些名稱存,混淆讀者和許多自動化的工具。唯一的例外是重新發(fā)布對外的API時可以考慮使用。
7、模塊中前后具有雙下劃線的變量名
像__all__ , __author__ , __version__ 等這樣的模塊中的變量名(也就是名字里有兩個前綴下劃線和兩個后綴下劃線),應該放在文檔字符串的后面,以及除from __future__ 之外的import表達式前面。Python要求將來在模塊中的導入,必須出現在除文檔字符串之外的其他代碼之前。
比如:
二、字符串引號
Python中單引號字符串和雙引號字符串都是相同的。注意盡量避免在字符串中的反斜杠以提高可讀性。
根據PEP 257, 三個引號都使用雙引號。
三、表達式和語句中的空格
在下列情況下,避免使用無關的空格:
1、緊跟在小括號,中括號或者大括號后。
2、緊貼在逗號、分號或者冒號之前。
3、然而,冒號在切片中就像二元運算符,在兩邊應該有相同數量的空格(把它當做優(yōu)先級最低的操作符)。在擴展的切片操作中,所有的冒號必須有相同的間距。例外情況:當一個切片參數被省略時,空格就被省略了。
4、緊貼在函數參數的左括號之前。
5、緊貼索引或者切片的左括號之前。
6、為了和另一個賦值語句對齊,在賦值運算符附件加多個空格。
其他建議
1、避免在尾部添加空格。因為尾部的空格通常都看不見,會產生混亂:比如,一個反斜杠后面跟一個空格的換行符,不算續(xù)行標記。有些編輯器不會保留尾空格,并且很多項目(像CPython)在pre-commit的掛鉤調用中會過濾掉尾空格。
總是在二元運算符兩邊加一個空格:賦值(=),增量賦值(+=,-=),比較(==,,!=,,=,in,not,in,is,is not),布爾(and, or, not)。
如果使用具有不同優(yōu)先級的運算符,請考慮在具有最低優(yōu)先級的運算符周圍添加空格。有時需要通過自己來判斷;但是,不要使用一個以上的空格,并且在二元運算符的兩邊使用相同數量的空格。
2、在指定函數 關鍵字參數 或者 默認參數 值的時候,不要在=附近加上空格。
3、功能型注釋應該使用冒號的一般性規(guī)則,并且在使用 ->的時候要在兩邊加空格。(參考下面的功能注釋得到能夠多信息)
4、當給有類型備注的參數賦值的時候,在=兩邊添加空格(僅針對那種有類型備注和默認值的參數)。
5、復合語句(同一行中的多個語句)通常是不允許的。
6、雖然有時候將小的代碼塊和 if/for/while 放在同一行沒什么問題,多行語句塊的情況不要這樣用,同樣也要避免代碼行太長!
四、注釋
與代碼自相矛盾的注釋比沒注釋更差。修改代碼時要優(yōu)先更新注釋!
注釋是完整的句子。如果注釋是斷句,首字母應該大寫,除非它是小寫字母開頭的標識符(永遠不要修改標識符的大小寫)。
如果注釋很短,可以省略末尾的句號。注釋塊通常由一個或多個段落組成。段落由完整的句子構成且每個句子應該以點號(后面要有兩個空格)結束,并注意斷詞和空格。
非英語國家的程序員請用英語書寫你的注釋,除非你120%確信代碼永遠不會被不懂你的語言的人閱讀。
1、注釋塊
注釋塊通常應用在代碼前,并和這些代碼有同樣的縮進。每行以 '# '(除非它是注釋內的縮進文本,注意#后面有空格)。
注釋塊內的段落用僅包含單個 '#' 的行分割。
2、行內注釋
慎用行內注釋(Inline Comments) 節(jié)儉使用行內注釋。 行內注釋是和語句在同一行,至少用兩個空格和語句分開。行內注釋不是必需的,重復羅嗦會使人分心。
不推薦:
但是有時,很有必要:
加了以后對理解代碼很有幫助的情況下,關鍵處才加。
3、文檔字符串
文檔字符串的標準參見:PEP 257。
為所有公共模塊、函數、類和方法書寫文檔字符串。非公開方法不一定有文檔字符串,建議有注釋(出現在 def 行之后)來描述這個方法做什么。
更多參考:PEP 257 文檔字符串約定。注意結尾的 """ 應該單獨成行,例如:
單行的文檔字符串,結尾的 """ 在同一行。
4、版本標簽
如果你必須在源文件中包含git、Subversion、CVS或RCS crud信息,放置在模塊的文檔字符串之后,任何其他代碼之前,上下各用一個空行:
五、命名規(guī)范
Python庫的命名約定有點混亂,不可能完全一致。但依然有些普遍推薦的命名規(guī)范的。新的模塊和包 (包括第三方的框架) 應該遵循這些標準。對不同風格的已有的庫,建議保持內部的一致性。
1、最重要的原則
用戶可見的API命名應遵循使用約定而不是實現。
2、命名風格
以下是常見的命名方式:
b(單個小寫字母)
B(單個大寫字母)
lowercase (小寫字母)
lower_case_with_underscores (使用下劃線分隔的小寫字母)
UPPERCASE( 大寫字母)
UPPER_CASE_WITH_UNDERSCORES (使用下劃線分隔的大寫字母)
CapitalizedWords(首字母大寫的單詞串或駝峰縮寫)
注意: 使用大寫縮寫時,縮寫使用大寫字母更好。故 HTTPServerError 比 HttpServerError 更好。
mixedCase(不同于首字母大寫,第一個單詞的首字母小寫)
Capitalized_Words_With_Underscores(帶下劃線,首字母大寫,巨丑無比)
還有一種風格使用短前綴分組名字。這在Python中不常用, 但出于完整性提一下。例如,os.stat()返回的元組有st_mode, st_size, st_mtime等等這樣的名字(與POSIX系統(tǒng)調用結構體一致)。
X11庫的所有公開函數以X開頭, Python中通常認為是不必要的,因為屬性和方法名有對象作前綴,而函數名有模塊名為前綴。
下面講述首尾有下劃線的情況:
_single_leading_underscore:(單前置下劃線): 弱內部使用標志。 例如"from M import " 不會導入以下劃線開頭的對象。
single_trailing_underscore_(單后置下劃線): 用于避免與 Python關鍵詞的沖突。 例如:
__double_leading_underscore(雙前置下劃線): 當用于命名類屬性,會觸發(fā)名字重整。 (在類FooBar中,__boo變成 _FooBar__boo)。
__double_leading_and_trailing_underscore__(雙前后下劃線):用戶名字空間的魔法對象或屬性。例如:__init__ , __import__ or __file__,不要自己發(fā)明這樣的名字。
3、命名約定規(guī)范
避免采用的名字:
決不要用字符'l'(小寫字母el),'O'(大寫字母oh),或 'I'(大寫字母eye) 作為單個字符的變量名。一些字體中,這些字符不能與數字1和0區(qū)別。用'L' 代替'l'時。
包和模塊名:
模塊名要簡短,全部用小寫字母,可使用下劃線以提高可讀性。包名和模塊名類似,但不推薦使用下劃線。
模塊名對應到文件名,有些文件系統(tǒng)不區(qū)分大小寫且截短長名字,在 Unix上不是問題,但當把代碼遷移到 Mac、Windows 或 DOS 上時,就可能是個問題。當然隨著系統(tǒng)的演進,這個問題已經不是經常出現。
另外有些模塊底層用C或C++ 書寫,并有對應的高層Python模塊,C/C++模塊名有一個前置下劃線 (如:_socket)。
類名:
遵循CapWord。
接口需要文檔化并且可以調用時,可能使用函數的命名規(guī)則。
注意大部分內置的名字是單個單詞(或兩個),CapWord只適用于異常名稱和內置的常量。
異常名:
如果確實是錯誤,需要在類名添加后綴 "Error"。
全局變量名:
變量盡量只用于模塊內部,約定類似函數。
對設計為通過 "from M import " 來使用的模塊,應采用 __all__ 機制來防止導入全局變量;或者為全局變量加一個前置下劃線。
函數名:
函數名應該為小寫,必要時可用下劃線分隔單詞以增加可讀性。 mixedCase(混合大小寫)僅被允許用于兼容性考慮(如: threading.py)。
函數和方法的參數:
實例方法第一個參數是 'self'。
類方法第一個參數是 'cls'。
如果函數的參數名與保留關鍵字沖突,通常在參數名后加一個下劃線。
方法名和實例變量:
同函數命名規(guī)則。
非公開方法和實例變量增加一個前置下劃線。
為避免與子類命名沖突,采用兩個前置下劃線來觸發(fā)重整。類Foo屬性名為__a, 不能以 Foo.__a訪問。(執(zhí)著的用戶還是可以通過Foo._Foo__a。) 通常雙前置下劃線僅被用來避免與基類的屬性發(fā)生命名沖突。
常量:
<...