A. python怎麼使用cython
1. Cython是什麼?
它是一個用來快速生成Python擴展模塊(extention mole)的工具
語法是Python和c的混血
Cython作為一個Python的編譯器,在科學計算方面很流行,用於提高Python的速度,通過OpenMPI庫還可以進行吧並行計算。
2. Cython安裝(Windows)
我的環境是win7 x64, python27, vs2010
安裝的基礎是有一個c編譯器(這里以vs2010為例)
從http://cython.org下載安裝包,解壓到一目錄,進入該目錄,在cmd命令行中執行
python setup.py install
註:執行過程可能遇到問題:Windows下pip安裝包報錯:Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat
解決方案:下載Microsoft Visual C++ Compiler for Python 2.7,點擊直接安裝即可。
3. 例子
例3.1:入門
創建hello.pyx,內容如下
def say_hello():
print "Hello World!"
創建setup.py,內容如下
from distutils.core import setup
from Cython.Build import cythonize
setup(name = 'Hello world app',
ext_moles = cythonize("hello.pyx"))
編譯Cython代碼
step1: 把.pyx文件被Cython便以為.c文件
step2: 把.c文件編譯為可導入的使用模塊.so(Windows下為.pyd)文件
1
2
python setup.py build
python setup.py install
註:可能出現問題:Unable to find vcvarsall.bat
原因:Python 2.7 會搜索 Visual Studio 2008.如果你電腦上沒有這個版本的話就會報錯。
如果裝的是vs2010,那麼在cmd命令行中執行
1
SET VS90COMNTOOLS=%VS100COMNTOOLS%
如果裝的是vs2010,那麼在cmd命令行中執行
1
SET VS90COMNTOOLS=%VS110COMNTOOLS%
執行
1
2
3
>>> import hello
>>> hello.say_hello()
Hello World!例3.2 通過靜態類型提高速度
在Cython中可以通過標記靜態類型來提高速度,凡是標記為靜態類型的部分都會將動態語言類型變為簡單的c代碼,從而提速。
但是如果濫用靜態類型,會降低可讀性,甚至因類型設置不當導致錯誤類型檢查造成速度降低。
例3.2.1 靜態類型變數
Python原生態代碼
compute.pyx
def f(x):
return x ** 2 - x
def integrate_f(a, b, N):
s = 0
dx = (b - a) / N
for i in range(N):
x += f(a + i * dx)
return s * dx
setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(
name = 'Hello world app',
ext_moles = cythonize("compute.pyx"),
)
test.py
import compute
import time
starttime = time.clock()
compute.integrate_f(3.2, 6.9, 1000000)
endtime = time.clock()
print "read: %f s" %(endtime - starttime)
執行
1
2
3
python setup.py build
python setup.py install
python test.py
結果
1
read: 0.332332 s
使用靜態變數替換後的代碼
compute2.pyx
def f(double x):
return x ** 2 - x
def integrate_f(double a, double b, int N):
cdef int i
cdef double s, dx
s = 0
dx = (b - a) / N
for i in range(N):
s += f(a + i * dx)
return s * d
setup2.py
from distutils.core import setup
from Cython.Build import cythonize
setup(
name = 'Hello world app',
ext_moles = cythonize("compute2.pyx"),
)
test2.py
import compute2
import time
starttime = time.clock()
compute2.integrate_f(3.2, 6.9, 1000000)
endtime = time.clock()
print "read: %f s" %(endtime - starttime)
執行
1
2
3
python setup.py build
python setup.py install
python test.py
結果
1
read: 0.109200s
結論
該測試用例,使用靜態類型速度是不使用靜態類型的3倍。
例3.2.2 靜態類型函數
把compute2.pyx中的函數變為
cdef double f(double x):
return x ** 2 - x
def integrate_f(double a, double b, int N):
cdef int i
cdef double s, dx
s = 0
dx = (b - a) / N
for i in range(N):
s += f(a + i * dx)
return s * dx
結果
1
read: 0.084859 s
結論:比例子3.2.1速度又快了
例3.3 調用C函數
cdef extern from "math.h":
double sin(double)
double cos(double)
cpdef double Sin(double x):
return sin(x)
cpdef double Cos(double x):
return cos(x)
cpdef: 對於Python可使用的函數使用(為了使得在以後的Python程序中調用Sin,Cos函數,用cpdef,而不用cdef)
cdef: 對於C可使用的函數使用
請注意,上面的代碼聲明了 math.h 里的函數,提供給 Cython 使用。C編譯器在編譯時將會看到 math.h 的聲明,但 Cython 不會去分析 math.h 和單獨的定義。
B. C++靜態代碼掃描工具都有哪些
工具非常多,各個工具通常會以插件的形式嵌入在各種IDE中,本人目前最偏愛cpplint,其實是就一個python腳本,幫助檢查是否符合GoogleC++Style的標准規范。
C. python的ide有哪些
分享的這幾個IDE工具希望會對你的開發有幫助。
1.Pyscripter
Pyscriptor是一個開源的Python集成開發環境,很富有競爭力,同樣有諸如代碼自動完成、語法檢查、視圖分割文件編輯等功能。
2. Wing
Wing是一個Python語言的超強IDE,適合做互動式的Python開發.Wing IDE同樣支持自動代碼完成、代碼錯誤檢查、開發技巧提示等,而且Wing IDE也支持多種操作系統,包括Windows、Linux和Mac OS X。
3. Emacs
Emacs是一個可擴展的文本編輯器,同樣支持Python開發.Emacs本身以Lisp解釋器作為其核心,而且包含了大量的擴展。
4. Pycharm
Pycharm是一個跨平台的Python開發工具,是JetBrains公司的產品.其特徵包括:自動代碼完成、集成的Python調試器、括弧自動匹配、代碼折疊.Pycharm支持Windows、MacOS以及Linux等系統,而且可以遠程開發、調試、運行程序。
5. Sublime Text
SublimeText也是適合Python開發的IDE工具,SublimeText雖然僅僅是一個編輯器,但是它有豐富的插件,使得對Python開發的支持非常到位。
6. Vim
Vim是一個簡潔、高效的工具,也適合做Python開發。
7. Komodo Edit
Komodo Edit是一個免費的、開源的、專業的Python IDE,其特徵是非菜單的操作方式,開發高效。
8. Eclipse with PyDev
Eclipse+PyDev插件,很適合開發Python Web應用,其特徵包括自動代碼完成、語法高亮、代碼分析、調試器、以及內置的交互瀏覽器。
很多時候,一個好的工具能夠對於編程的輔助作用是非常大的,無論是在python培訓期間還是工作之後,都脫離不了各種IDE工具應用。
D. python第三方庫為什麼
Python第三方庫幾乎都可以在github或者 pypi上找到源碼。源碼包格式大概有zip 、 tar.zip、 tar.bz2。解壓這些包,進入解壓好的文件夾,通常會有一個setup.py的文件。打開命令行,進入該文件夾。運行以下命令,就能把這個第三庫安裝到系統里:
Python
python setup.py install
1
python setup.py install
或者藉助pip,則不需要解壓:pip install package.zip
E. 風變編程的Python課程學完效果如何
一、Python簡介
Python是一種用來編寫應用程序的高級程序設計語言,TIOBE程序語言排行榜2015年12月的排名如下:
Python實現強勢逆襲,而且我相信,隨著時間的推移,國內Python語言未來前景也是一片向好。
Python的特點是優雅簡單,易學易用(雖然我感覺還是有一些概念不容易理解),Python的哲學是盡量用最少的,最簡單易懂的代碼實現需要的功能。Python適宜於開發網路應用,腳本寫作,日常簡單小工具等等。Python的缺點是效率較低,但是在大量的場合效率卻不是那麼重要或者說Python不是其性能瓶頸,所以不要太在意。其次是2.x-3.x的過渡使得許多3.x還缺少很多2.x下的模塊,不過也在完善中。其次就是源代碼無法加密,發布Python程序其實就是發布源代碼。
二、基礎語法要點
1.如果一個字元串中有許多需要轉義的字元,而又不想寫那麼多'',那麼可以用 r'...' 表示 '...'內的內容不轉義。
2.Python可用'''...'''來表示多行內容,如:
123456>>>print('''line1line2line3''')line1line2line3
3.Python的邏輯運算and, or, not 分別對應C語言中的&&, ||, !.
4.Python的整數與浮點數大小都沒有范圍。
5.Python中除法有兩種: '/'除出來必是浮點數, '//'除出來是整數,即地板除。
6.Python中一切皆引用。每個對象都有一個引用計數器(內部跟蹤變數)進行跟蹤,引用計數值表示該對象有多少個引用,當初次產生賦給變數時,引用計數為1,其後沒進行下列行為中的任意一種都會增加引用計數:
123賦值: a=b用作函數參數傳遞: func(a)成為容器對象的一個元素: lis=[1,2,a]
以下任意一種行為都會減少引用計數:
1234del銷毀:dela變數另賦給其他對象:a=False對象從容器中刪除: lis.remove(a)身在的容器被銷毀:dellis
7.深拷貝與淺拷貝的概念與對比,有點復雜,看這篇文章
8.list,tuple和dict,set
list:為列表,是一個有序集合,類似於數組但又比數組功能強大,可以隨時append,pop元素,下標從0開始,且下標為加n模n制,即lis[-1] = lis[len-1],下標范圍[-len,len-1].
tuple:為元組,類似於list,但list為可變類型,而tuple不可變,即沒有append,pop等函數。一個建議是為了安全起見,能用tuple代替list盡量用tuple。如果tuple只有一個元素,要寫成如(1,)以避免歧義。
dict:字典類型,存放key-value鍵值對,可以根據key迅速地找出value,當然,key必須是不可變類型,如下是錯誤的:
12345>>> dic={[1,2]:'value'}Traceback (most recent call last):File"<pyshell#10>", line1,in<mole>dic={[1,2]:'value'}TypeError: unhashabletype:'list'
list與dict的優劣對比:
1234567dict:1.插入,查找速度快,跟key的數目無關2.需佔用大量內存,內存浪費嚴重list:1.插入,查找速度慢,O(n)的復雜度,隨元素個數增加而增加2.佔用內存小
dict內部存放的順序和key放入的順序是沒有關系的
set:set與dict類似,相當於只有key沒有value的dict,每個key不同,set間有 &, | 等操作對應集合的交,並操作。
三、函數
1.函數是對象,函數名即是指向對應函數對象的引用,所以可以將函數名賦給一個變數,相當於給函數起一個『別名』。
123>>> mmm=max>>> mmm(1,2,3)3
2.Python函數可以返回」多個值「,之所以打引號,是因為實際上返回的多個值拼成了一個元組,返回這個元組。
3.定義默認參數需要牢記:默認參數必須指向不變對象。否則第一次調用和第二次調用結果會不一樣,因為可變的默認參數調用後改變了。
4.可變參數:傳入的參數個數是可變的,可以是0個或多個。可變參數會將你傳入的參數自動組裝為一個tuple。在你傳入的list或tuple名字前加一個 * 即說明傳入的是可變參數。習慣寫法為*args。
5.關鍵字參數:傳入0個或多個含參數名的參數,這些參數被自動組裝成一個dict。習慣寫法**kw,如**a表示把a中所有的鍵值對以關鍵字參數的形式傳入kw,獲得一個dict,這個dict是a的一份拷貝,對kw改動不會傳遞到a
6.命名關鍵字在函數定義中跟在一個*分割符後,如
12deffunc(a,b,*,c,d):pass
c,d為命名關鍵字參數,可以限制調用者可以傳入的參數名,同時可以提供默認值。
7.參數定義順序:必選參數,默認參數,可變參數/命名關鍵字參數,關鍵字參數。
8.切片操作格式為lis[首下標:尾下標:間隔],如果都不填,即lis[::]則代表整個容器lis
9.用圓括弧()括起來一個列表生成式創建一個生成器generator,generator保存生成演算法,我們可以用next(g)取得生成器g的下一個返回值。生成器的好處就是我們不需要提前生成所有列表元素,而是需要時再生成,這在某些情況下可以節省許多內存。演算法也可以不是列表生成式而是自定義函數,只需在函數定義中包含yield關鍵字。
10.map()和rece(): 二者都是高階函數。map()接收兩個參數,一個是函數,一個是Iterable序列,map將傳入的函數依次作用在序列每一個元素上,並把結果作為新的Iterator返回。rece()類似累積計算版的map(),把一個函數作用在一個序列上,每次接收兩個參數,將結果繼續與序列的下一個元素做累積計算。
利用map和rece編寫一個str2float函數,如把字元串'123.456'轉換成浮點數123.456:
123456789101112131415(s):deff1(x,y):returnx*10+ydefchar2num(s):return{'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]deff2(x,y):returnx*0.1+ya,b=s.split('.')print('a=',a)print('b=',b)returnrece(f1,map(char2num,a))+0.1*rece(f2,map(char2num,b[::-1]))print('str2float('123.456') =', str2float('123.456'))
11.fliter()函數過濾序列,類似於map()作用於每一元素,根據返回值是True或者False決定舍棄還是保留該元素。函數返回一個Iterator。
12.sorted()函數可實現排序,類似於C++庫中的sort()函數,但是比其更加簡潔,語法為sorted(lis,key=func,reverse=T/F)
key函數可實現自定義的排序規則,reverse表示升序還是降序。
13.一個函數可以返回一個函數,但是返回時該函數並未執行,所以返回函數中不要引用任何可能發生變化的變數,否則會出現邏輯錯誤。
14.裝飾器(decorator): 當需要增強函數的功能卻不希望修改函數本身,那麼可以採用裝飾器這種運行時動態增加功能的方式,增加的功能卸載裝飾器函數中。如在執行前後列印'begin call'和'end call',可以這樣做:
12345678910111213141516importfunctoolsdeflog(func):@functools.wraps(func)#為了校正函數簽名,最好寫上defwrapper(*args,**kw):print('begin call')f=func(*args,**kw)print('end call')returnfreturnwrapper@logdefhah():print('hahahaha')hah()
123
begin callhahahahaend call
15.偏函數: functools.partial(),作用是將一個函數的某些參數固定住,作為新函數的參數,即固定住該參數,返回一個新函數,使調用更簡單。
四、面向對象編程
1.Python實例變數可以自由地綁定任何屬性
2.為了不讓內部屬性不被外部訪問,在屬性的名稱前加上兩個下劃線__,這樣就變成了一個私有變數(private),注意,不能直接訪問不代表一定不能訪問,事實上,加雙下劃線後Python就會將其改名為『_class名__name』,所以還是可以這樣來訪問這個『私有』變數。
3.對於靜態語言,如果要求傳入一個class類型的對象,那麼傳入的對象必須是class類型或者其子類,否則將無法調用class中的方法,而Python這樣的動態語言有『鴨子類型』一說,即不一定要傳入class類型或其子類,而只要保證傳入的對象中有要使用的方法即可。
4.如果想要限制實例可以綁定的屬性,那麼在定義class時定義一個__slots__變數即可,例如:
12classStudent(object):__slots__=(『name』,』age』)
注意,__slots__限制的屬性對當前類實例起完全限製作用,且與子類共同定義其__slots__,也就是說子類可以定義自己的__slots__,子類實例允許定義的屬性就是自身的__slots__加上父類的__slots__,即並集。
5.@ property裝飾器可以使一個getter方法變成屬性,如果方法名為me,那麼@me.setter裝飾器則可使一個setter方法變成屬性。這樣可以使代碼更簡短,同時可對參數進行必要的檢查。
6.通過多重繼承,可使子類擁有多個父類的所有功能。
7.在類中__call__方法可使實例對象像函數那樣直接調用,作用即是該方法定義的過程。
8.ORM(Object Relational Mapping 對象關系映射),就是把關系資料庫的一行映射為一個對象,也就是一個類對應一個表。ORM的實現需要通過metaclass元類修改類的定義。元類可以改變類創建時的行為。
五、調試
1.Python調試方法:
(1)直接列印
(2)斷言
(3)pdb
(4)IDE
六、IO編程
1.序列化: 把變數從內存中變成可存儲或傳輸的過程稱之為序列化。Python用pickle模塊實現序列化。序列化之後,就可以把序列化後的內容存儲到磁碟上或者通過網路進行傳輸。pickle.mps()將對象序列化成一個bytes,而pickle.loads()可以根據bytes反序列化出對象。
2.pickle雖好,但是它專為Python而生,所以要在不同語言間傳遞對象,最好還是xml或者json,而json表示格式是一個字元串,更易讀取,且比xml快,所以更加適宜於對象序列化。Python內置了json模塊,相應方法仍然是mps()和loads()。
3.但是在默認情況下,有些對象是無法序列化的,所以我們有時還需要定製轉換方法,告訴json該如何將某類對象轉換成可序列為json格式的{}對象。如下即是一個轉換方法:
123456defmantodict(std):return{'name': std.name,'age': std.age,'id': std.id}
七、進程與線程
1.Python用mutiprocessing模塊來實現多進程。
2.如果要大量創建子進程,可以使用進程池:
1frommultiprocessingimportPool
示例如下:
12345678....p=Pool(4)foriinrange(5):p.apply_async(long_time_task, args=(i,))print('Waiting for all subprocesses done...')p.close()p.join()print('All subprocesses done.')
要使用進程池需新建Pool對象,對Pool對象調用join()使等待池中所有子進程運行完畢,調用join()方法之前必須調用close(),且此後無法再新加子進程。
3.使用subprocess模塊可以方便的啟動並管理一個子進程,控制其輸入輸出。
4.進程間通信使用Queue,Pipes實現。
5.threading模塊管理線程。threading.lock()創建線程鎖,防止同時訪問互斥資源造成的錯誤,示例如下:
1234567lock=threading.Lock()...lock.acquire()...change(mutex)...lock.release()
6.ThreadLocal可以解決參數在一個線程中各個函數之間互相傳遞的問題。
7.managers模塊實現分布式進程。
八、正則表達式與常用內建模塊
1.re模塊進行正則表達式編譯和匹配,如果該表達式需要匹配很多次,那麼最好進行編譯從而大大節省時間。
正則表達式匹配郵箱例子:
12345678910importrehah=re.compile('[0-9a-zA-Z]+[.[0-9a-zA-Z]+]*@[0-9a-zA-Z]+.[a-z]{2,3}')print(hah.match('[email protected]').group())print(hah.match('[email protected]').group())i=1whilei <10:r=input('請輸入郵箱:')print(hah.match(r).group())i=i+1
2.datetime模塊進行日期和時間的處理,每一個時間對應一個timestamp,我們把1970年1月1日 00:00:00 UTC+00:00時區的時刻稱為epoch time,記為0(1970年以前的時間timestamp為負數),當前時間就是相對於epoch time的秒數,稱為timestamp。字元串和datetime也可以相互轉換,採用strptime()方法,字元串轉換為datetime時需要設定一個識別格式,其中
1%Y-%m-%d%H:%M:%S
分別表示年-月-日 時-分-秒。
從datetime得出月份,星期等字元串用strftime()方法,其中:
1%a,%b%d%H:%M
分別表示星期, 月份 日期 時:分。
示例:
12345678910fromdatetimeimportdatetimer='2015-11-23 12:01'dt=datetime.strptime(r,'%Y-%m-%d %H:%M')print(dt)week=dt.strftime('%a %b %d, %H:%M')print(week)2015-11-2312:01:00Mon Nov23,12:01
3.collections是Python內建的一個集合模塊,提供了許多有用的集合類。
4.Base64是一種任意二進制到文本字元串的編碼方法,常用於在URL、Cookie、網頁中傳輸少量二進制數據。
5.struct模塊用來解決bytes和其他二進制數據類型的轉換。
6.Python的hashlib提供了常見的哈希演算法,如MD5,SHA1等等。hashlib實現簡單登錄:
importhashlibdb={'michael':'','bob':'','alice':''}defget_md5(ostr):md5=hashlib.md5()md5.update(ostr.encode())returnmd5.hexdigest()deflogin(user, password):r=get_md5(password)fornameindb:ifdb[name]==r:returnTruereturnFalseprint(login('bob','abc999'))True
7.Python的內建模塊itertools提供了非常有用的用於操作迭代對象的函數。
8.urllib提供了一系列用於操作URL的功能。如GET,POST...
9.PIL(Python Imaging Library Python圖像庫)是一個強大的圖像處理標准庫,功能強大卻又簡單易用。現在的名字叫做Pillow。可以如下安裝Pillow:
1pip3 install pillow
從下面生成數字驗證碼的程序可以窺其一斑:
九、網路編程和電子郵件
1.網路編程主要是TCP和UDP的編程,示例見【Python網路編程】利用Python進行TCP、UDP套接字編程
2.SMTP是發送郵件的協議,Python內置對SMTP的支持,可以發送純文本郵件、HTML郵件以及帶附件的郵件。Python對SMTP支持有smtplib和email兩個模塊,email負責構造郵件,smtplib負責發送郵件。Python內置一個poplib模塊,實現了POP3協議,可以直接用來收郵件。由於現在絕大多數大型郵件服務商都採取了反垃圾郵件措施,所以這部分的簡單實驗並沒有成功,還需進一步研究,等遇到具體情況再說。
3.Python內嵌了sqlite資料庫,還可以自行安裝連接mysql,MySQL是當前最流行的開源資料庫,在行業內有著廣泛的應用。
十、Web開發和非同步IO
1.WSGI(Web Server Gateway Interface) 伺服器網關介面。
2.Python web 開發框架:
-Flask:流行的Web框架
-Django:全能型Web框架
-web.py:一個小巧的Web框架
-Bottle:和Flask類似的Web框架
-Tornado:Facebook的開源非同步Web框架
3.協程
F. 靜態分析是指
經濟領域概念
靜態分析是一種分析經濟現象的均衡狀態以及有關的經濟變數達到均衡狀態所需要條件的分析方法。[1]而不考慮經濟現象達到均衡狀態的過程,它完全抽象掉了時間因素和具體的變化過程,是一種靜止地、孤立地考察某種經濟事物的方法。
網路
靜態分析
經濟領域概念
靜態分析是一種分析經濟現象的均衡狀態以及有關的經濟變數達到均衡狀態所需要條件的分析方法。[1]而不考慮經濟現象達到均衡狀態的過程,它完全抽象掉了時間因素和具體的變化過程,是一種靜止地、孤立地考察某種經濟事物的方法。
中文名
靜態分析
外文名
static analysis
指標
總量指標、相對指標、平均指標、標志變異指標等
應用
靜態計算機科學、經濟學、工程、力學、機械
釋義
根據既定的外生變數值求得內生變數的分析方法
內涵
靜態分析法是根據既定的外生變數值求得內生變數的分析方法,是對已發生的經濟活動成果,進行綜合性的對比分析的一種分析方法。
如研究均衡價格時,舍掉時間、地點等因素,並假定影響均衡價格的其他因素,如消費者偏好、收入及相關商品的價格等靜止不變,單純分析該商品的供求達於均衡狀態的產量和價格的決定。簡單地說就是抽象了時間因素和具體變動的過程,靜止地孤立地考察某些經濟現象。它一般用於分析經濟現象的均衡狀態以及有關經濟變數達到均衡狀態所需要的條件。
常用的靜態分析法有:相對數分析法、平均數分析法、比較分析法、結構分析法、因素替換分析法、綜合計算分析法、價值系數分析法等。
指標
G. python ide哪個好用
第一款:Eric6
Eric6是一個用Python編寫的Python IDE,雖然它使用Qt5UI框架提供一個比IDLE復雜很多的UI。但是它的入門需要一些組件,因為Eric6不像傳統的本地平台程序一樣應用。它本質上是一個大的Python包和幾個重量級依賴,例如Qt5的Python綁定。結果是:Eric6入門需要對Python包管理的理解,因此它不太可能會吸引初學者用戶。從這方面而言,安裝程序腳本會提供反饋,以便您知道哪些包需要提取和安裝以完成設置過程。
Eric6有著設備齊全的顯著特點。它包含現代的IDE,如類瀏覽、版本控制等通常的實用工具,但它也集成了對Python專用功能如unittest、PyLint和cx_freeze應用程序分發系統的支持。在Eric6創建的新項目,也可以建成PyQT4中/5GUI和控制台應用程序,因為底層庫已安裝,但額外的開發工具,如Qt的窗體設計器不包括在默認設置之內。
第二款:Wing IDE
作為Python程序員的智能開發環境,WingIDE強調專門為Python用戶設計的功能集成。這不僅僅是跨代碼庫的重構功能或使用多個Python解釋器。它還包括與許多流行的Python框架、包和第三方應用程序的詳細集成。RaspberryPi用戶也可以使用Wing IDE進行開發。不僅如此,Wing IDE是一個Python初學者非常好上手的工具。
第三款:Pyzo
Pyzo是一個小IDE,主要針對科學計算的用戶,有一個小工具集:編輯器、互動式shell、文件瀏覽器、源結構瀏覽器和一些其他的設施。它主要用於與庫的快速交互,您可以在Python的REPL中鍵入命令或執行單個文件,而不是正式的應用程序開發。在這個意義上,它不太適合那些想要創建應用程序,更適合那些想要使用Python作為工作台環境的人。
第四款:Thonny
Thonny,一個專門為初學者使用該語言設計的小型的IDE,是一個更加簡單的選擇。在Windows、Mac或Linux上可用,它還可以節省用戶下載或配置的Python解釋器。Python的最新版本與Thonny捆綁在一起,IDE默認開箱可用。也就是說,你可以隨時交換任何其他Pythonruntime。
第五款:NINJA-IDE
作為一個獨立的項目,NINJA-IDE可以像專業級開發工具,如ActiveState"s Komodo
IDE或PyCharm,不僅在開發人員的經驗,而且它的功能集是由Python用戶構建和為了Python用戶構建的。例如,NINJA-IDE的首選項對話框有一個標簽,用於選擇在運行程序時使用的Python解釋器,以及用戶啟動或設置解釋器使用的所有各種命令行選項的復選框,這是非常方便地。IDE中的另一個選項卡默認顯示為Migration2to3,它可以分析為Python2.X編寫的腳本並提出建議。
第六款:VisualStudio Code
微軟的簡單和精益的代碼編輯器從其支持不同語言的擴展的瀚海星系中獲得力量。Python開發人員有一堆VisualStudioCode擴展,但最流行,最容易,最重要的是DonJayamanne的擴展。它與每一個最新版本的Python保持同步,它集成了所有你想要的好東西的支持:代碼片段、代碼靜態分析、自動完成與科學工具集成,如Jupyter、重構、單元測試、調試以及更多更多。
H. sublime text 怎麼添加python
Sublime Text 3 (ST3) 是一個輕量級的跨平台文字編輯器,尤以其輕快的速度,易用性和強大的社區支持而著稱。它一經面世便被認為是一個傑出的編輯器,而它真正的強大之處在於你可以使用 Package Control 來增加它的功能以及可以進行各種自定義設置。
在本文章中,我們將會看到如何將 Sublime Text 打造成為 Python 的全棧開發環境(從前端到後端),如何通過自定義主題和插件來增強它的基本功能,並且還將會涉及到很多使 ST3 變得更加強大的常用的命令,特性以及快捷鍵。
本教程將假定你使用的是 Mac 電腦並且習慣於使用終端。如果你使用的是 Windows 或者 Linux 操作系統,本文涉及到的一些命令將有可能會有所不同,但是你應該仍然可以很容易地通過 Google 來獲取到與本教程相關的解答。
在我們開始之前,讓我們先討論一下我所謂的」全棧」具體指的是什麼。
在現在的 HTML5 以及移動設備開發中,Javascript 簡直無處不在。是的,無處不在!僅僅使用 Python 基於某個框架比如 Django 或者 Flask 進行開發是不夠的。如果你想從始至終真正的自己開發一個網站的話,你必須熟悉 Javascript(以及 Javascript 的一大堆的框架),REST API(含狀態傳輸 API),響應式設計,當然還有 HTML 和 CSS,以及其他許多東西。現在讓我們來面對一個問題:就像其他任何一個手藝人一樣,為了成為一個最厲害的程序員,你的工具必須犀利,你的開發環境必須被打造成全棧開發——那就是我們馬上將要開始的工作…
特性
讓我們從 ST3 的一些默認特性開始著手吧…
Split Layouts 允許你將你的許多文件放到很多分割開來的視窗中。如果你正在進行以測試為目的的開發(將 Python 代碼放在一個視窗中,而測試腳本放在另一個視窗中)或者正在進行前端開發(將 HTML 代碼放在一個視窗里,CSS/Javascript 代碼放在另一個視窗里)的時候將會非常有用。
Vintage Mode 讓你能夠在 ST3 中使用 vi 模式。
Chrome-like Tabs 讓你在多個文件中切換變得更加方便。
Automatic loading of the last session 幫你自動打開你上次關閉的時候編輯器中所有打開的文件。我總是一直開著 ST3,而且其中打開著一大堆項目——當我重啟電腦以後, 它能夠自動幫我打開所有的這些文件和文件夾。
Code Snippets 允許你通過一兩個簡單的關鍵字就能寫出一段常用的代碼片(Snippets),從而增加你的生產效率。比如,你只需要打開一個文件,輸入 「lorem」 然後敲擊 tab 鍵,就會自動生成一段亂數假文(譯者註: 一種用於測試文章或文字在不同字型、版型下看起來的效果等的文字)。又比如在 Python 代碼中,你可以輸入 「defs」 然後敲擊 tab 鍵,你就能得到一段通用的函數定義。
同時,你還可以點擊 Tools > New Snippet 來創建屬於你自己的代碼片。請參照這個 文檔來獲取幫助,也可以在 這里 查看我個人用到的一些 snippets。
自定義 Sublime Text 3
在你下載完 ST3 以後…
在命令行中添加 subl 命令
就像 TextMate 的 mate 命令一樣,Sublime Text 擁有一個叫做 subl 的命令行工具,可以用來通過終端打開一個文件或者一整個文件夾。
你需要建立一個指向 subl 二進制文件的符號鏈接來使 subl 命令有效:
Python
1
$ ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" ~/bin/subl
嘗試使用以下命令來打開 Sublime 來確保鏈接生效了:
Python
1
$ subl
如果以上命令沒有效果,你可能需要將 /bin 添加到你的環境變數中:
Python
1
$ echo "export PATH=~/bin:$PATH" >> ~/.profile
然後重新嘗試第一步。
如果你仍然遇到問題,嘗試查看 這篇 文章來獲取幫助。 或者你可以看看如何在 Windows和 Linux 中建立符號鏈接。
現在你就可以通過下述命令來打開文件或者文件夾了:
Python
1
2
3
4
5
6
7
8
# open the current directory
$ subl .
# open a directory called tests
$ subl ~/Documents/test
# open a file called text.txt
$ subl test.txt
如果路徑中含有空格,你必須使用雙引號將路徑括起來:
Python
1
$ subl "~/Documents/test/my test file.txt"
想要查詢所有可用的命令,請打開幫助文件:
Python
1
$ subl --help
安裝 Package Control
為了使用眾多的 插件 來擴展 Sublime 的功能,你需要安裝一個叫做 Package Control 的插件管理器——這個東西你必須要手動安裝。但是一旦你安裝好了以後,你就可以使用 Package Control 來安裝,移除或者升級所有的 ST3 插件了。
點擊 這里 從 Sublime Text 3 官方獲取用於安裝的代碼。依次點擊 View > Show Console 打開 ST3 的控制台。在控制台中粘貼剛才的代碼,然後點擊回車。最後重啟 ST3。
現在你可以通過快捷鍵 cmd+shift+P 打開 Package Control 來安裝其他的插件了。輸入 install 然後你就能看見屏幕上出現了 Package Control: Install Package,點擊回車然後搜索你想要的插件。
其他一些相關命令如下:
List Packages 顯示所有已安裝的插件
Remove Packages 移除一個指定的插件
Upgrade Package 更新一個指定的插件
Upgrade/Overwrite All Packages 更新所有已安裝的插件
請查閱官方 文檔 獲取更多的命令。
創建自定義配置文件
你可以通過一個基於 JSON 的配置文件來充分的自定義 Sublime Text,這使得轉移或者同步你的自定義文件到另一個系統變得非常容易。首先,我們需要新建我們自己的配置文件。我們最好是為不同的系統環境和編程語言各自創建一個配置文件。
依次點擊 Sublime Text > Preferences > Settings – User 來創建一個配置文件。在該文件中添加一個空的 JSON 類然後就可以在其中寫入你的配置內容了。如下所示:
Python
1
2
3
4
5
6
7
{
// base settings
"auto_complete": false,
"sublimelinter": false,
"tab_size": 2,
"word_wrap": true
}
如果想為特定的編程語言新建配置文件的話,請點擊 Sublime Text > Preferences > Settings – More > Syntax Specific – User。然後按照 LANGUAGE.sublime-settings 的格式保存該配置文件。例如想新建一個 Python 專用的配置文件,請將該文件保存為 Python.sublime-settings。
你完全可以按照你自己的喜好來進行各項配置;不過我強烈推薦以我的這份 配置文件 以及 Python 配置 作為基礎,然後修改成你所需要的內容。
一個可選項: 你可以使用 Dropbox 來同步你的所有配置。你只需要將你的配置文件上傳到 Dropbox 然後就可以將你的配置同步到你的任意一台設備上了。
你可以在 Sublime Text Unofficial Documentation 找到一些非常好的參考配置。
主題
ST3 為你提供了完全自定義化一個適合自己主題的能力。當然,你如果不是那麼的挑剔的話,你可以通過 Package Control 從許許多多的由 Sublime 社區設計的 主題 中下載一個。 在下載之前你可以通過 ColorSublime 來預覽這些主題。
廣受歡迎的的 Soda Dark 和極簡風格的 Flatland 是我個人最喜歡的兩個主題。
在安裝完了主題以後, 請務必更新你的配置文件. Sublime Text > Preferences > Settings – User:
Python
1
2
3
4
{
"theme": "Flatland Dark.sublime-theme",
"color_scheme": "Packages/Theme - Flatland/Flatland Dark.tmTheme"
}
插件
除了那些主題以外,我還會使用以下這一些插件來提升我的工作效率。
SideBarEnhancements
SideBarEnhancements 擴展了側邊欄中菜單選項的數量,從而提升你的工作效率。諸如」New file」 和 「Duplicate」 這樣的選項對於 ST3 來說實在是太重要了, 我甚至覺得 ST3 本來就應該提供這些功能。而且僅憑 「Delete」 這一個功能就讓這個插件值得下載。這個功能將你會在你刪除文件的時候把它放入回收站。雖然這個功能乍一看沒什麼用,但是當你沒有使用這樣的功能而徹底刪除了一個文件的時候,除非你用了版本管理軟體,否則你將很難恢復這個文件。
現在就下載吧!
Anaconda
Anaconda 是一個終極 Python 插件。它為 ST3 增添了多項 IDE 類似的功能,例如:
Autocompletion 自動完成,該選項默認開啟,同時提供多種配置選項。
Code linting 使用支持 pep8 標準的 PyLint 或者 PyFlakes。因為我個人使用的是另外的 linting 工具,所以我會在 Anaconda 的配置文件 Anaconda.sublime-settings中將 linting 完全禁用。操作如下: Sublime > Preferences > Package Settings > Anaconda > Settings – User: {"anaconda_linting": false}
McCabe code complexity checker 讓你可以在特定的文件中使用 McCabe complexity checker. 如果你對軟體復雜度檢查工具不太熟悉的話,請務必先瀏覽上邊的鏈接。
Goto Definitions 能夠在你的整個工程中查找並且顯示任意一個變數,函數,或者類的定義。
Find Usage 能夠快速的查找某個變數,函數或者類在某個特定文件中的什麼地方被使用了。
Show Documentation: 能夠顯示一個函數或者類的說明性字元串(當然,是在定義了字元串的情況下)
你可以在這里,或者通過 ST3 的 Package Settings: Sublime Text > Preferences > Package Settings > Anaconda > README 來查看所有這些特性。
SublimeCodeIntel 是另外一個非常流行的插件,它的許多特性與 Anaconda 類似。我建議同時也試試它。
Djaneiro
Djaneiro 支持 Django 模版和關鍵字高亮以及許多實用的代碼片(snippets)功能。其中的 snippets 絕對是省時神器。你可以通過很少幾個關鍵字就能創建許多常見的 Django 代碼塊比如 templates,models,forms,以及 views。請查看官方文檔獲取 snippets 列表。
我個人非常喜歡的以下兩個用於創建 template 的代碼片:輸入 var 就可以新建 {{ }},而輸入 tag 就能新建 {% %}。
requirementstxt
Requirementstxt 可以為你的 requirements.txt 文件提供自動補全,語法高亮以及版本管理功能。
SublimeLinter
SublimeLinter 是 ST3 的一個代碼靜態檢查工具框架(linter)。這個插件本身來說並不包含任何的一個 linter,但是你可以通過在 Package Control 中輸入 SublimeLinter-[linter_name] 的方式來安裝一個 linter。你可以點擊這里查看官方的 linter。同時你還可以在 Package Control 中查看到許多的第三方 linter。請點擊這里查看安裝說明。
對於 Python 的代碼靜態檢查器,我建議使用 SublimeLinter-pyflakes 和 SublimeLinter-pep8。
與此同時,我也會使用 SublimeLinter-jshint, SublimeLinter-pyyaml, SublimeLinter-csslint,SublimeLinter-html-tidy,以及 SublimeLinter-json。
以上大多數的 linter 都需要先安裝一些依賴庫才能使用,所以在安裝前請務必閱讀他們的安裝說明。
你可以通過修改用戶自定義的 SublimeLinter.sublime-settings 文件來對你的每個 linter 個性化:Sublime Text > Preferences > Package Settings > SublimeLinter > Settings – User. 例如我通過以下代碼來忽略 pep8 中的錯誤和警告:
Python
1
2
3
4
5
6
7
8
"pep8": {
"@disable": false,
"args": [],
"excludes": [],
"ignore": "E501,C0301,W0142,W0402,R0201,E1101,E1102,C0103,R0901,R0903,R0904,C1001,W0223,W0232,W0201,E1103,R0801,C0111",
"max-line-length": 100,
"select": ""
},
GitGutter
GitGutter 讓 ST3 能在左邊欄的位置顯示一個小圖標,用以表示在最後一次提交以後,代碼是否有追加,修改或者刪除。
如果你想讓該插件支持分布式的版本管理軟體(Git,SVN,Bazaar 和 Mercurial)。請查看 Modific。
FTPSync
FTPSync 能夠將你的項目和遠程文件進行同步。你只需要打開文件便可以下載更新(如果你的遠端文件比本地更加新的話),而且如果你對本地文件做出了修改可以立即同步到遠程伺服器。這是非常棒的同步本地文件和遠程文件的方法。你可以通過以下的方法來添加你的遠程伺服器:Sublime Text > Preferences > Package Settings > FTPSync > Setup FTPSync.
Sample settings:
Python
1
2
3
4
5
6
7
8
9
10
11
{
'primary': {
host: 'ftp.mywebsite.com',
username: 'johnsmith',
password: 'secretpassword',
path: '/www/',
upload_on_save: true,
tls: true
}
}
我個人喜歡把密碼設為 null 因為我不想讓我的密碼出現在配置文件中。這樣 FTPSync 會在我每次保存完文件後要求我輸入密碼。
AdvancedNewFile
AdvancedNewFile 可以讓你在 ST3 中使用簡單的幾個快捷鍵便創建一個新的文件夾或者一個新的文件:
你只需要通過幾個快捷鍵便可以打開 AdvancedNewFile 的輸入框。然後輸入路徑和文件名。當你按下回車鍵後,文件便被創建了。除此之外,如果目標文件夾並不存在的話,該文件夾將會被自動建立。在默認情況下,你創建的文件的路徑將會顯示在狀態欄中。
請查看 Github 上的這篇文檔來獲取更為詳細的使用說明。特別建議請詳細閱讀TAB自動補全(Tab Completion)以及預定義別名(Predefined Aliases)部分。
我把「cmd+n」設置為了通過 AdvancedNewFile 創建新文件的快捷方式。該快捷鍵可以通過修改 Key Bindings – User file 來實現 Sublime Text > Preferences > Package Settings > AdvancedNewFile > Key Bindings – User:
Python
1
2
3
[
{ "keys": ["cmd+n"], "command": "advanced_new_file_new"}
]
你也可以更改默認打開的文件夾路徑:Sublime Text > Preferences > Package Settings > AdvancedNewFile > Settings – User
Python
1
{"default_initial": "/Users/michaelherman/Documents/repos"}
這樣我創建新文件的時候,/Users/michaelherman/Documents/repos將會自動被添加到路徑最前方,因為99%的情況下我都會把我的腳本放在這個路徑下。
Emmet
Emmet,以前叫做 Zen Coding,讓你可以通過簡單的縮寫來創建 HTML 或者 CSS 的代碼塊。
例如,你只需要輸入感嘆號!,然後按下 tab 鍵,便可以在一個 HTML 文件中創建一段帶有幾個基本標簽的 HTML5 文檔類型的代碼:
Python
1
2
3
4
5
6
7
8
9
10
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
</html>
請查看官方文檔或者速查手冊獲取更多信息。
Markdown Preview
Markdown Preview 可以用來預覽和編譯 markdown 文件。
你可以打開 Package Manager 然後輸入 Markdown Preview 來查看可用的命令:
Markdown Preview: Python Mrakdown: 在瀏覽器中預覽
Markdown Preview: Python Mrakdown: 導出 HTML 文件
Markdown Preview: Python Mrakdown: 拷貝到剪貼板
Markdown Preview: Github風格Markdown: 在瀏覽器中預覽
Markdown Preview: Github風格Markdown: 導出 HTML 文件
Markdown Preview: Github風格Markdown: 拷貝到剪貼板
Markdown Preview: 打開Markdown速查手冊
一旦你完成轉換,你之後的所有保存都會立即反映到轉換的文件中。
快捷鍵
跳轉到任意內容 (「cmd+p」) 用來快速查找和打開文件。你僅僅只需要工程中文件的一部分路徑或者文件名你就可以很容易的打開這個文件。這在一個大型的 Django 工程中顯得非常方便。
跳轉到指定行 (「ctrl+g」) 讓你在當前文件中跳轉到指定行數。
跳轉到標志 (「cmd+r」) 可以列出當前文件中所有的函數或者類,讓你更方便查找。你可以通過輸入關鍵字來查找你所需要的函數或者類。
跳轉到行首 (cmd+left-arrow-key) 與 跳轉到行尾 (cmd+right-arrow-key)
刪除當前行(ctrl+shift+k)
多重編輯 是我迄今為止最喜歡的快捷鍵
Python
1
2
1.選定一個單詞,點擊 **「cmd+d」** 來選擇同樣的單詞,再次點擊 **「cmd+d」** 繼續選擇下一個單詞…
2.或者 **「cmd+單擊」** 來指定多個你想要同時修改的地方。
塊編輯 (option+left-mouse-click) 用於選擇一整塊的內容。通常在整理 CSV 文件的時候用於刪除空白內容。
如果想了解更多關於快捷鍵的內容,請看一下這篇文章。
自定義命令
你可以很容易地使用 Python 來編輯你自己的自定義命令和快捷鍵組合。目前我個人使用的有以下這些:
拷貝當前文件路徑到剪貼板 – 鏈接
關閉除當前活動標簽頁以外的所有其他標簽頁 – 鏈接
通過文件選項打開你的 Package 文件夾(Sublime > Preferences > Browse Packages),然後打開 User 文件夾,接下來將上述的 Python 文件添加到 「/Sublime Text 3/Packages/User」 文件夾中。最後請在 Key Bindings – User file (Sublime Text > Preferences > Package Settings > AdvancedNewFile > Key Bindings – User) 文件中完成快捷鍵綁定。
Python
1
2
3
4
5
6
7
8
9
10
11
12
[
// Copy file name
{
"keys": ["cmd+shift+c"],
"command": "_path_to_clipboard"
},
// Close all other tabs
{
"keys": ["cmd+alt+w"],
"command": "close_tabs"
}
]
I. 如何利用python在pycharm上進行語音合成
pycharm 通過 SFTP 遠程編輯項目的配置
{這個相當於代碼同步,類似git上傳,同步後你可以在伺服器上直接運行上傳的代碼;這個配置好後,才能在pycharm遠程調試時候將代碼上傳到伺服器正確位置/正確路徑上}
打開pycharm,File -> Settings…( Ctrl + Alt + s ) -> Deployment
點擊 + 按鈕,添加一個
如果你發現你的運行配置中沒有 Django 相關的項,請在項目設置的 Django 中勾選 Enable Django Support。
運行配置的設置有兩點需要注意。Python Interpreter 需要選中之前建立的遠程解釋器。Path mappings 處,需要把本機的 manage.py 與 Linux 上的關聯起來,比如:
C:/Evolution/Python/django_website/manage.py <=> /home/onlyice/work/django_website/manage.py
這可能是 PyCharm 的 bug:在使用遠程解釋器後,PyCharm 並不會自動將 Django 運行配置中的 manage.py 文件定位到 Linux 上的那份,而是會嘗試使用下面的命令來啟動 Django 調試 Server:
/usr/bin/python2 manage.py C:/Evolution/Python/django_website/manage.py
自然就找不到文件了。所以使用了 Path mappings 作為一種 hack 手段來解決。
這時就可以打斷點調試啦
Trouble Shooting
Q: 點擊調試運行失敗,顯示 「Cant set remote tunneling」
A: 調試時 PyCharm 調用將 Python Debug Server (pydevd.py) 綁定在一個隨機埠上,再使用 SSH 的埠轉發將數據通過 SSH 埠轉到 Debug Server 去。需要檢查你的 sshd 配置 (默認是 /etc/ssh/sshd_config) 是否禁用了 TCP 轉發 (AllowTcpFowarding),這個配置默認是打開的。
皮皮blog
出錯問題
pycharm channel is not opened
pycharm不能同步deployment中設置的文件內容了,在remote host窗口中打開文件提示the file is identical to local但實際上完全不同,上傳多次才能成功,或者乾脆就提示channel is not opened。應該和sftp有關。
目前還沒找到具體原因,可能是伺服器問題,過會就自己好了。
也可能是pycharm的問題,或者系統的問題?希望解決的可以留言告知一下,謝謝!
[Can't Download From Remote Server via SFTP – JetBrains IntelliJ]
pandas出錯
pycharm console import pandas Backend Qt4Agg is interactive backend. Turning interactive mode on. : cannot connect to X server
import pandas : cannot connect to X server
重啟pycharm,或者也不知道怎麼了就好了,不報錯了。。。
運行出錯
ssh://[email protected]:22/home/piting/ENV/anaconda3/bin/python3 -u /home/piting/mine/python_workspace/Oth/Competition/TianChi/Regression.py
/home/piting/ENV/anaconda3/bin/python3: can't open file '/home/piting/mine/python_workspace/Oth/Competition/TianChi/Regression.py': [Errno 2] No such file or directory
點出remote host標簽,發現沒有這個目錄,目錄下也沒有這個文件
解決:
mkdir -p 代碼目錄
再在remote host中右鍵 》 upload here
ref: [PyCharmRemote Debugging指南]
[pycharm奇淫技巧]*
[使用Pycharm進行Python遠程開發]
[Deployment in PyCharm]
J. 為啥我的Python這么慢
Pythn是動態類型而不是靜態類型的,這意味著,在程序執行時,解釋器並不知道變數的類型。對C語言來說,編譯器在聲明變數的時候就知道其類型了;對Python來說,程序執行時只知道一個變數是某種Python對象。
對於下面的C代碼
int a = 1;
int b = 2;
int c = a + b;
編譯器始終知道a和b是整型,在執行相加運算時,流程如下:
把<int> 1賦值給a
把<int> 2賦值給b
調用binary_add<int, int>(a, b)
把結果賦值給c
實現同樣功能的Python代碼如下
a = 1
b = 2
c = a + b
解釋器只知道1和2是對象,但是並不知道這個對象的類型。所以解釋器必須檢查每個變數的PyObject_HEAD才能知道變數類型,然後執行對應的相加操作,最後要創建一個新的Python對象來保存返回值,大致流程如下:
把1賦值給a
設置a->PyObject_HEAD->typecode為整型
設置a->val = 1
把2賦值給b
設置a->PyObject_HEAD->typecode為整型
設置b->val = 2
調用binary_add<int, int>(a, b)
a->PyObject_HEAD獲取類型編碼
a是一個整型;值為a->val
b->PyObject_HEAD獲取類型編碼
b是一個整型,值為b->val
調用binary_add<int, int>(a->val, b->val)
結果為整型,存在result中
創建對象c
設c->PyObject_HEAD->typecode為整型
設置c->val為result
動態類型意味著任何操作都會涉及更多的步驟。這是Python對數值操作比C語言慢的主要原因
Python是解釋型語言
上面介紹了解釋型代碼和編譯型代碼的一個區別。智能的編譯器可以提前預見並優化重復或不需要的操作,這會帶來性能的提升。編譯器是一個大的話題,這里不會展開。
Python的對象模型會帶來低效的內存訪問
和C語言的整數對比時,我們指出了Python多了額外一層信息。現在來看看數組的情況。在Python中我們可以使用標准庫中提供的List對象;而在C語言中我們會使用基於緩沖區的數組。
最簡單的NumPy數組是圍繞C數據構建的Python對象,也就是說它有一個指向連續數據緩存區的指針。而Python的list具有指向連續的指針緩沖區的指針,這些指針每個都指向一個Python對象,結合上面的例子,這些Python對象是一個整數對象。這個結構像下面這樣
很容易看出,如果你正在執行按順序逐步完成數據的操作,numpy的內存布局比Python的內存布局更為高效,無論是存儲成本還是訪問的時間成本。
為什麼使用Python
鑒於Python天生的低效率,我們為什麼還要使用Python呢?種種理由大致可以歸結為:動態類型使得Python比C更容易使用。Python非常的靈活和寬容,這種靈活性可以有效地利用開發時間,並且在那些確實需要C和Fortran優化的場合,Python可以輕松鏈接到已編譯的庫中。這也是Python在科學社區的使用率不斷增長的原因。經提到了一些結論性的東西,下面我們用Python的一些工具來做一些驗證。
下面的實驗使用到了python, ipython, numpy,版本信息如下:
python:3.6.5
1.13.3
In [1]: import sys
In [2]: import numpy
In [3]: sys.version[:5]
Out[3]: '3.6.5'
In [4]: numpy.__version__
Out[4]: '1.13.3'
本次實驗使用機器64位的機器,如果是32位的機器話,下面提到的一些struct可能會有所不同。
整數
Python的整數使用起來非常簡單。
In [5]: x = 42
In [6]: print(x)
42
介面的簡單性掩蓋了底層的復雜。在之前的內容里有提到過Python整數的內存布局。現在我們使用Python內置的ctypes模塊來自省整數類型,前提是需要知道在C API中Python整數類型的定義。
在CPython中,變數x存儲在一個名為_longobject的struct中,源碼見Include/longintrepr.h
struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
}
其中PyObject_VAR_HEAD是一個宏,在Include/object.h中定義的結構如下
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size;
} PyVarObject;
其中PyObject在Include/object.h中定義如下
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
}
其中_PyObject_HEAD_EXTRA是一個在Python版本中通常不使用的宏。
將上面的信息結合起來,可以得到下面的結構
struct _longobject {
long ob_refcnt;
PyTypeObject *ob_type;
size_t ob_size;
long ob_digit[1];
}
這裡面ob_refcnt變數是對象的引用計數,ob_type是指向包含該對象所有類型信息和方法定義的結構的指針,ob_digit保存實際的數值。
有了上面的知識,可以開始使用ctypes模塊來觀察時間的對象結構並提取上面的信息。
現在來用Python定義一個C的struct
In [7]: import ctypes
In [9]: class IntStruct(ctypes.Structure):
...: _fields_ = [
...: ("ob_refcnt", ctypes.c_long),
...: ("ob_type", ctypes.c_void_p),
...: ("ob_size", ctypes.c_ulong),
...: ("ob_digit", ctypes.c_long)
...: ]
...:
...: def __repr__(self):
...: return (
...: "IntStruct(ob_digit)={self.ob_digit}, refcount={self.ob_refcnt}"
...: ).format(self=self)
...:
現在用42來做實驗。在Python中,id方法會返回對象的內存地址:
In [10]: num = 42
In [11]: IntStruct.from_address(id(42))
Out[11]: IntStruct(ob_digit)=42, refcount=61
可以看到ob_digit指向了內存中的正確位置。但是這里只創建了一個對象,為什麼引用次數是61呢?
事實證明,這是一個性能優化,Python使用了很多小的整數,如果為每一個數字都創建一個PyObject,會消耗掉不少內存。出於這個考慮,Python將一些常用的數字做了單例實現,這樣每個數字在內存中只有一份拷貝。換句話說,如果在這個范圍內創建一個新的Python整數時,只是創建了一個對該數值對象的引用。
In [16]: x = 42
In [17]: y = 42
In [18]: id(x) == id(y)
Out[18]: True
上面的例子中,x和y都指向了同一個內存地址。在使用更大的數的時候,等式就不成立了
In [19]: x = 1234
In [20]: y = 1234
In [21]: id(x) == id(y)
Out[21]: False
Python解釋器啟動時候會創建很多的整數對象;可以看看這些對象的引用分布
%matplotlib osx
import matplotlib.pyplot as plt
import sys
plt.loglog(range(1000), [sys.getrefcount(i) for i in range(1000)])
plt.xlabel('integer value')
plt.ylabel('reference count')
Out[8]: Text(0,0.5,'reference count')
可以看到0被引用了數千次,一般情況下,引用的頻率隨著整數值的增加而減少。
再來看看ob_digit對應的值
In [8]: all(i == IntStruct.from_address(id(i)).ob_digit for i in range(256))
Out[8]: True
如果更細心一點,就可以發現,對於大於256的值,ob_digit就不能對應到正確的值了:在Objects/longobject.c中對數值有一些移位操作,這也是Python對一些大整數的處理方式。
比如
In [11]: 2 ** 100
Out[11]:
這個值顯然是超過了long類型的范圍了。
List類型
現在來看看一個更復雜的數據類型:List。同樣能在Include/listobject.h中找到List類型的struct結構:
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item;
Py_ssize_t allocated;
} PyListObject;
和之前一樣,得到有效的結構體如下:
typedef struct {
long ob_refcnt;
PyTypeObject *ob_type;
Py_ssize_t ob_size;
PyObject **ob_item;
long allocated;
} PyListObject;
其中PyObject **ob_item指向list的數據,ob_size指出list中數據的個數。
In [3]: class ListStruct(ctypes.Structure):
...: _fields_ = [("ob_refcnt", ctypes.c_long),
...: ("ob_type", ctypes.c_void_p),
...: ("ob_size", ctypes.c_ulong),
...: ("ob_item", ctypes.c_long), # PyObject** pointer cast t
...: o long
...: ("allocated", ctypes.c_ulong)]
...:
...: def __repr__(self):
...: return ("ListStruct(len={self.ob_size}, "
...: "refcount={self.ob_refcnt})").format(self=self)
試驗一下
In [8]: L = [1, 2, 3, 4]
In [9]: ListStruct.from_address(id(L))
Out[9]: ListStruct(len=4, refcount=1)
為確保得到的結果是正確的,對這個list增加幾個引用,看看會不會影響引用計數:
In [10]: tup = [L, L]
In [11]: ListStruct.from_address(id(L))
Out[11]: ListStruct(len=4, refcount=3)
使用ctypes可以創建由之前IntStruct對象組成的復合結構
In [20]: Lstruct = ListStruct.from_address(id(L))
In [21]: PtrArray = Lstruct.ob_size * ctypes.POINTER(IntStruct)
In [22]: L_values = PtrArray.from_address(Lstruct.ob_item)
看看每個元素的值
In [23]: [ptr[0] for ptr in L_values]
Out[23]:
[IntStruct(ob_digit=1, refcount=4705),
IntStruct(ob_digit=2, refcount=1102),
IntStruct(ob_digit=3, refcount=559),
IntStruct(ob_digit=4, refcount=726)]
NumPy的數組
同樣的,我們來看看numpy中的數組。其C-API定義的結構見numpy/core/include/numpy/ndarraytypes.h,這里用的numpy版本是1.13.3,不同版本的結構可能有所不同。
In [25]: np.__version__
Out[25]: '1.13.3'
現在用ctypes來創建一個numpy數組的結構吧。
In [31]: class NumpyStruct(ctypes.Structure):
...: _fields_ = [("ob_refcnt", ctypes.c_long),
...: ("ob_type", ctypes.c_void_p),
...: ("ob_data", ctypes.c_long), # char* pointer cast to long
...: ("ob_ndim", ctypes.c_int),
...: ("ob_shape", ctypes.c_voidp),
...: ("ob_strides", ctypes.c_voidp)]
...:
...: @property
...: def shape(self):
...: return tuple((self.ob_ndim * ctypes.c_int64).from_address(self.ob_shape))
...:
...: @property
...: def strides(self):
...: return tuple((self.ob_ndim * ctypes.c_int64).from_address(self.ob_strides))
...:
...: def __repr__(self):
...: return ("NumpyStruct(shape={self.shape}, "
...: "refcount={self.ob_refcnt})").format(self=self)
新建一個numpy數組試試In [32]: x = np.random.random((10, 20)) In [33]: xstruct = NumpyStruct.from_address(id(x)) In [34]: xstruct Out[34]: NumpyStruct(shape=(10, 20), refcount=1)
可以看到已經拿到了正確的shape。現在看看引用計數的情況
In [35]: L = [x, x, x]
In [36]: xstruct
Out[36]: NumpyStruct(shape=(10, 20), refcount=4)
現在可以看看裡面的數據了。
In [37]: x = np.arange(10)
In [38]: xstruct = NumpyStruct.from_address(id(x))
In [39]: size = np.prod(xstruct.shape)
In [40]: arraytype = size * ctypes.c_long
In [41]: data = arraytype.from_address(xstruct.ob_data)
In [42]: [d for d in data]
Out[42]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
上面的data變數存儲了Numpy數組中定義的連續的內存塊,可以改一下其中的值。
In [43]: x[4] = 555
In [44]: [d for d in data]
Out[44]: [0, 1, 2, 3, 555, 5, 6, 7, 8, 9]
上面的例子可以證明x和data指向了同一塊連續內存。
比較Python的list和numpy的ndarray的內部結構,明顯可以看出numpy的數據對於表示同類型的數據列表來說簡單的多。
結語
Python很慢,正如上面所說,一個重要原因是類型的間接定址,這也是Python對開發者友好的原因。同時,Python本身也提供了可用於破解Python對象的工具,通過使用這些工具可以解析CPython的一些內部行為。
上