?
前言
其實不太想寫跟Java無關(guān)的東西,但是實在憋得難受,想想一個項目組的其他同事都回家過年了,就剩下我一個苦逼的還在堅守在戰(zhàn)斗一線,醬油也打了一段時間了,再憋下去難受了,所以趁著過年前發(fā)一篇博文吧,也可以打發(fā)下時間,何樂而不為呢?
?
廢話說了一籮筐,回到正題。Python相信有不少開發(fā)人員,尤其是運維人員應(yīng)該是非常熟悉的,那么請大家聽我好好掰扯下Python究竟能夠做什么,如果你覺得Python是個好東西,那么也請你嘗試著使用它為你的項目增添一點色彩。筆者本文所使用的Python版本為3.x,盡管和Python2.x相比,3.x 在語法層面的改變是比較大的,但是請大家不要去 糾結(jié) 這些問題,只需要聽筆者為你一一道來即可。
?
目錄
一、Python簡介;
二、Python的下載與安裝;
三、第一個Python程序;
四、基本語法的使用
五、函數(shù)的使用;
六、流程控制語句;
七、面向?qū)ο筇匦裕?
八、I/O操作;
九、線程操作;
?
一、Python簡介
其實看筆者這篇博文的朋友,更關(guān)心的是Python是什么,以及究竟能夠為我們的項目帶來什么好處?其實筆者在第一次接觸Python的時候,立馬就被這 炫酷和簡易 的語法吸引住了,因為使用Python所帶來的好處太多了。簡單來說,Python其實是一門基于 解釋性/編譯性 的動態(tài)、面向?qū)ο缶幊陶Z言,這里筆者要稍微解釋下所謂的解釋性/編譯性問題。對Java有所了解的開發(fā)人員應(yīng)該知道,JIT編譯器所帶來的改變對于Java程序的運行性能是起到了 至關(guān)重要 的作用,使得Java程序的運行性能有了 質(zhì)的飛躍 ,毫 不遜色 于C/C++編寫的程序的執(zhí)行性能,這是因為HotSpot VM中的JIT編譯器會在運行時結(jié)合 熱點探測功能 將頻繁被調(diào)用的代碼標(biāo)記為“ 熱點代碼 ”然后經(jīng)過 分層優(yōu)化編譯技術(shù) 將Java代碼直接 編譯為本地代碼。這種運行時的編譯技術(shù),必然比靜態(tài)編譯擁有更好的 編譯質(zhì)量 ,畢竟 靜態(tài)編譯是無法準(zhǔn)確預(yù)估程序在執(zhí)行過程中所有的運行時熱點的 。
?
和Java一樣,Python的執(zhí)行引擎究竟是基于解釋執(zhí)行呢,還是編譯執(zhí)行,或者是混合執(zhí)行都取決于底層的VM(筆者博文全部統(tǒng)稱為VM)。目前比較常見的Python VM有:CPython、IPython、PyPy,以及Jython(HotSpot VM)。關(guān)于這幾個VM大家可以去官網(wǎng)了解下。簡單來說,CPython是Python的官方缺省解釋器,基于解釋運行;而IPython是建立在CPython之上的一個交互式解釋器;PyPy內(nèi)置有JIT編譯器,執(zhí)行性能相對而言會比前幾種高效許多倍;而Jython其實就是將Python代碼編譯為字節(jié)碼后運行在HotSpot VM中,結(jié)合HotSpot VM的解釋器+JIT編譯器的 混合執(zhí)行引擎 ,可以達(dá)到高效執(zhí)行的效果,不過更重要的是使用Jython可以很好的與Java代碼交互(并不僅限于特定的語言,CPython可以是C、C++)。是的,你沒有聽錯,簡單到你會以為Python天生就是為了粘合Java代碼而生!因此Python還有一個很好聽的名字,那就是“ 膠水語言 ”。
?
當(dāng)然不是說Python語言的作用就是純粹的粘合其他語言一起執(zhí)行,盡管Python最大的優(yōu)點確實是這個,但是任何高級語言能做的事情,Python都能夠做到,而且 代碼產(chǎn)出效率極快 。因此大部分企業(yè)都會在項目需求較緊的時候使用Python快速上線,然后后續(xù)逐漸使用其他適合的編程語言逐步替換之前由Python編寫的功能模塊,以此保證代碼的 結(jié)構(gòu)嚴(yán)謹(jǐn)性 。
?
二、Python的下載與安裝
如果你Java功力很強(qiáng),那么學(xué)習(xí)Python就是輕而易舉,這就好比《倚天屠龍記》中的張無忌掌握九陽神功后,學(xué)習(xí)太極拳的輕車熟路,其實道理都是 一樣 的。當(dāng)然如果你本身骨子里并無任何編程語言基礎(chǔ),學(xué)習(xí)Python同樣也 不會感覺到吃力 ,因為相對于Java\C\C++之類的編程語言,Python的學(xué)習(xí)可以算是相當(dāng)簡單的。如果按照筆者的經(jīng)驗來判斷,除了比HTML稍微復(fù)雜點,幾乎 是個人都能夠輕而易舉的掌握Python這門語言 。筆者甚至在考慮,過年回家的時候,是否有必要教老媽使用Python編寫一個小程序?
?
又說了一大堆廢話,回到主題,Python的下載和安裝。大家可以登錄 https://www.python.org/ 下載Python,筆者本文所使用的版本并沒有采用最新的3.4.2,而是3.3.0,沒有特殊的寓意,因此你可以自由選擇和筆者保持一致的版本,同樣也可以下載最新的版本,當(dāng)然千萬不要下載Python2.x版本,畢竟它們在語法層面上的差距是非常大的。
?
當(dāng)成功下載好Python后,在安裝的時候記得勾選選項“path”,否則只能夠在安裝好后,手動配置Python的環(huán)境變量(PATH=安裝路徑)。當(dāng)大家成功安裝好Python后,為了檢驗是否安裝成功,大家可以通過控制臺,輸入命令“Python -V”(大寫V, Python大小寫敏感 )驗收結(jié)果,如果控制臺輸出的是Python的版本號,則意味著安裝成功,反之安裝失敗。
?
三、第一個Python程序
所謂工欲善其事必先利其器,在使用Python編寫程序之前,首先要做的就是準(zhǔn)備好Python的開發(fā)工具,當(dāng)然筆者不建議新手一上來就是用各種IDE,而是建議你使用文本編輯器就可以了,比如Editplus,它會是你初次接觸Python的利器,希望大家記住, 學(xué)習(xí)任何一門新技術(shù),或者新語言之前,必然首先需要記住一些常用的函數(shù)、語法風(fēng)格 ,而不是什么都是依靠IDE工具來“飯來張口,衣來伸手”,不要讓你的大腦過度偷懶,會生銹的。
?
當(dāng)然如果你使用Python有一斷時間了,或者正在準(zhǔn)備使用Python運用在項目中時,就有必要考慮工作效率的問題了,因為筆者也不希望你浪費過多的時間在回憶應(yīng)該調(diào)用那個函數(shù),以及函數(shù)的名字叫什么,否則你可能離打包走人不遠(yuǎn)了。簡單來說,Python的IDE工具非常多,如果是JYthon,那么使用PyDEV是非常好的,以插件的形式集成在神器Eclipse中,無疑為Java開發(fā)人員帶來了方便。當(dāng)然本文只是單純的講解Python的使用,并且VM也是使用CPython,因此Pycharm不得不說是編寫Python的好幫手。
?
筆者不打算啰嗦的為大家科普IDE工具應(yīng)該怎么使用,請自行Google。當(dāng)成功啟動IDE工具或者文本編輯器后,接下來我們就開始編寫我們的第一個Python程序,如下所示:
print("Hello World")
?
當(dāng)執(zhí)行上述程序時,控制臺將會輸出“Hello World”。納尼,你沒有看錯,Python就是這么簡單, 嚴(yán)格意義上按照模塊進(jìn)行劃分,不需要顯式的先編寫一個類、在編寫方法,再來寫語句 。嗦嘎德斯捏。
?
Sorry,筆者忘記了一件事情,按照慣例不應(yīng)該先講如何在IDE工具中或者文本編輯器中編寫Python代碼,而是應(yīng)該讓大家知道Python的交互式運行環(huán)境。沒關(guān)系,現(xiàn)在講似乎也不遲。Python其實有2種類型的運行環(huán)境,一種是基于交互式環(huán)境,而另外一種則是我們剛才使用到的傳統(tǒng)環(huán)境。這里筆者所指的交互式環(huán)境,其實更多應(yīng)用在測試、練習(xí)上,適合剛接觸Python的開發(fā)人員,畢竟在交互式環(huán)境中,寫一行代碼,立馬就可以得到結(jié)果,如下所示:
?
除了在剛開始學(xué)習(xí)Python的時候,或者在測試練習(xí)上會使用到Python自帶的交互式環(huán)境外,實際的項目開發(fā)過程中,這種做法并不常見,因為代碼 無法固化 ,每次都要重新編寫,意義何在?
?
四、基本語法的使用
筆者在本節(jié)中將會介紹Python的基本語法的使用,涵蓋了:變量的定義、運算符、表達(dá)式、數(shù)據(jù)類型、數(shù)據(jù)結(jié)構(gòu)等知識點。請不要責(zé)怪筆者的“ 不耐煩 ”,畢竟這些太過于基礎(chǔ)的技術(shù),筆者實在是不忍心 大費周章 ,浪費紙墨和口水去講解,畢竟后續(xù)還有其它的知識點,因此快速講解是筆者的風(fēng)格,希望理解。
?
簡單來說,變量其實就是屬性(后續(xù)重點講解);運算符其實用于計算,表達(dá)式由字面值、云算法和變量構(gòu)成;數(shù)據(jù)類型很簡單,跟Java一樣,Python同樣也是 強(qiáng)類型 的,不過在Python中定義一個變量,開發(fā)人員并不需要在變量標(biāo)示符之前顯式聲明變量的類型( PS:不顯式定義變量類型導(dǎo)致筆者曾經(jīng)一度以為Python是弱類型,結(jié)果試了下10+“100”,運行期報錯,OK,糾正下這個錯誤 );數(shù)據(jù)結(jié)構(gòu)簡單來說就是數(shù)據(jù)的存儲結(jié)構(gòu)和存儲方式。下面筆者使用一段簡單的代碼來匯總筆者本節(jié)提及過的所有知識點,如下所示:
#encoding=gbk #Python的基本語法結(jié)構(gòu) userName="JohnGao" age=28 sex=True hobbys=["看書","寫字","睡覺"] print("我的名字->" + userName) print("我的年紀(jì)->" + str(age)) print("我的性別->" + str(sex)) for hobby in hobbys: print("我的愛好->"+hobby,end="\t")
?
上述程序示例中,將會按照筆者書寫的順序串行執(zhí)行print輸出。可以發(fā)現(xiàn),在Python中,確實是大小寫敏感的,boolean類型的值,True和False首字母是必須要大寫;而筆者在輸出int類型和boolean類型的2個變量時,使用了強(qiáng)轉(zhuǎn),因為Python的一條語句輸出, 只能是同一種數(shù)據(jù)類型 ,而不能夠是多種(除非符號“,”分割)。關(guān)于筆者定義的線性表的數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù)結(jié)果集,然后又使用for循環(huán)的方式將其迭代,關(guān)于這一點,筆者稍后會做出解釋。
?
五、函數(shù)的使用
函數(shù)即方法 。除了可以在代碼中使用Python提供的缺省內(nèi)置函數(shù)外,開發(fā)人員也可以編寫自定義函數(shù)來實現(xiàn)程序的功能。當(dāng)然在正式開始講解如何在程序中編寫一個自定義函數(shù)之前,我們首先來看看Python究竟帶給了我們哪些驚喜?筆者示例幾個比較常用的Python內(nèi)置函數(shù),如下所示:
#encoding=gbk #求絕對值函數(shù) print(abs(-100)) #強(qiáng)制轉(zhuǎn)換函數(shù) print(str(100)) print(int("200")) print(float(2000)) print(bool(1)) #isinstance函數(shù) print(isinstance(100,(int,float)))
?
def testMethod1(): print("一個簡單的自定義函數(shù)") #定義一個無任何操作的空函數(shù) #pass關(guān)鍵字就是一個占位符 def testMethod2(): pass
def testMethod1(): value=100+1 return value print(testMethod1())
def testMethod1(): value1=100+1 value2="userName->JohnGao" return value1,value2 value1,value2=testMethod1() print(value1,value2) print(testMethod1())
#定義函數(shù)參數(shù) def testMethod1(userName,age): return userName,age userName,age=testMethod1("JohnGao",28) print(userName,age) #定義可變參數(shù) def testMethod1(*values): for value in values: print(value,end="\t") testMethod1(100,200,300)
#if-else語句 value = 50 if value < 10: pass else: pass #if-else-if多路分支語句 userName=input("猜猜我的名字:\n") if userName == "JohnGao": pass elif userName=="JohnGao1": pass else: pass #for循環(huán)語句 for i in range(10): pass value2=["1","2","3"] for j in value2: pass #while循環(huán)語句 value3=0 while value3<10: value3+=1
class Animal(object): pass
#繼承示例 class Animal(object): pass class Tiger(Animal): pass class Pig(Animal): pass
#晚期綁定 class Animal(object): def getName(self): pass class Tiger(Animal): def getName(self): print("我的名字叫做Tiger") class Pig(Animal): def getName(self): print("我的名字叫做Pig") def getName(Animal): print(Animal.getName()) #創(chuàng)建對象實例 animal = Tiger() getName(animal)
class Demo(object): userName="張三" __passWord="123456" def getName(self): pass demo = Demo() print(demo.userName) #print(demo.passWord)
#讀取目標(biāo)數(shù)據(jù)源的數(shù)據(jù) try: readValue=open("d:/test.txt","r") #讀取一行字符串 print(readValue.readline()) finally: if readValue: readValue.close() #向目標(biāo)數(shù)據(jù)源寫入數(shù)據(jù) try: writeValue=open("d:/test2.txt","w") #寫入一行字符串 writeValue.write("test...") finally: if writeValue: writeValue.close()
readValue.read()
#讀取目標(biāo)數(shù)據(jù)源的二進(jìn)制數(shù)據(jù)流 readValue=open("d:/test.txt","rw") #向目標(biāo)數(shù)據(jù)源寫入二進(jìn)制數(shù)據(jù)流 writeValue=open("d:/test2.txt","w")
#文件復(fù)制操作 def copy_method(file_path, save_path): if not isinstance(file_path,(str)): print("只支持所傳遞的參數(shù)為字符串") else: startTime=time.time() with open(file_path,"rb") as read_value: context = read_value.read() print("數(shù)據(jù)全部讀入完畢,數(shù)據(jù)大小為->" + str(len(context)/1024) + "KB") with open(save_path,"wb") as write_value: write_value.write(context) print("數(shù)據(jù)寫入完成...") print("耗時->" + str((time.time() - startTime) * 1000) + "ms") #"E:\\迅雷下載\\move.rmvb", "d:\\move.rmvb" #copy_method("d:/fengtong.rar", "d:\\fengtong2.rar"); #E:\\迅雷下載\\move.rmvb #文件復(fù)制操作2(適合大文件的讀寫) def copy_method2(file_path, save_path): if not isinstance(file_path,(str)): print("只支持所傳遞的參數(shù)為字符串") else: try: startTime=time.time() write_value = open(save_path,"wb") for read_value in open(file_path,"rb"): write_value.write(read_value) print("數(shù)據(jù)寫入完成...") print("耗時->" + str((time.time() - startTime) * 1000) + "ms") finally: if write_value: write_value.close()
import os def findFile(path): #列出當(dāng)前目錄下的所有文件及文件夾 files = os.listdir(path) for file in files: if os.path.isfile(file): print(file) else: os.chdir(os.path.abspath(file)) findFile(os.getcwd()) cwd=os.getcwd() parent="" for i in range(len(cwd.split("\\")) - 1): parent+=cwd.split("\\")[i] + "\\" #切換到上一級目錄 os.chdir(parent) filePath="D:\\test" os.chdir(filePath) findFile(filePath)
?
九、線程操作
其實筆者寫道這里,已經(jīng)有頂乏力了,為了避免爛尾,筆者就不長篇大論了(今天最后一天上班,木有心情寫了)。簡單來說,多線程指的就是并發(fā),當(dāng)然并發(fā)跟并行的概念還是要區(qū)分下,并發(fā)是構(gòu)建于單CPU上,而并行是構(gòu)建于多CPU上的并發(fā)執(zhí)行。因為我們知道多線程并不是真正意義上的多任務(wù)同時執(zhí)行,而是CPU會不停的做任務(wù)切換,交叉運行,看起來貌似是一起執(zhí)行(CPU切換平率快),但其實不是這樣,只有并行才是真正意義上的多任務(wù)同時執(zhí)行。
?
在Python中定義和使用線程很簡單,Python的API提供了2個模塊:thread和threading,threading對thread模塊進(jìn)行了封裝。絕大多數(shù)情況下,我們只需要使用threading這個模塊即可。啟動一個線程就是把一個函數(shù)傳入并創(chuàng)建Thread實例,然后調(diào)用start()開始執(zhí)行即可,如下所示:
def run(): for i in range(10): print(i) thread1=threading.Thread(target=run,name="線程A") thread1.start() #主線程繼續(xù)執(zhí)行 print("........")
?
既然談到線程,不得不提及的還有鎖機(jī)制,因為在并發(fā)環(huán)境下,多線程同時對一個資源進(jìn)行操作,會造成非線程安全問題,因此Python也提供有鎖機(jī)制,如下所示:
#獲取鎖 value="資源" lock=threading.Lock() def run(): try: lock.acquire() for i in range(10): print(threading.current_thread().name,value) finally: lock.release() thread1=threading.Thread(target=run,name="線程A") thread1.start() thread2=threading.Thread(target=run,name="線程B") thread2.start()
?
上述程序示例中,多個線程持有同一把鎖,只有當(dāng)前一個前程使用完并釋放鎖,隊列中的其他線程才能夠正常的訪問同一個資源,以此避免非線程安全問題。當(dāng)然值得注意的,在Python中,鎖的釋放并非是自動的,而是需要開發(fā)人員手動顯式的執(zhí)行release()函數(shù)進(jìn)行釋放,所以大家千萬要記得使用完之后 一定要記得解鎖 ,否則其他線程就會一直阻塞。
?
在并發(fā)場景下,使用鎖可以有效的避免線程安全問題,但是這也同時造成了另外一個問題的出現(xiàn),那就容易造成 線程死鎖 ,如下所示:
#encoding=gbk import threading,time resourceA="資源A" resourceB="資源B" #獲取鎖 lockA=threading.Lock() lockB=threading.Lock() def run1(): try: lockA.acquire() print("%s成功鎖住"%threading.current_thread().name,resourceA) print("%s準(zhǔn)備鎖住"%threading.current_thread().name,resourceB) time.sleep(1) lockB.acquire() print("%s成功鎖住"%threading.current_thread().name,resourceB) finally: lockB.release() lockA.release() def run2(): try: lockB.acquire() print("%s成功鎖住"%threading.current_thread().name,resourceB) print("%s準(zhǔn)備鎖住"%threading.current_thread().name,resourceA) lockA.acquire() print("%s成功鎖住"%threading.current_thread().name,resourceA) finally: lockA.release() lockB.release() thread1=threading.Thread(target=run1,name="線程A") thread1.start() thread2=threading.Thread(target=run2,name="線程B") thread2.start()
?
簡單來說,就是A線程鎖住A資源的時候,試圖獲取B鎖,但是B線程已經(jīng)搶先一步獲取到B鎖,這個時候A線程就必須等待,而B線程試圖獲取A鎖時,發(fā)現(xiàn)A鎖已經(jīng)被A線程獲取了,因此雙方都在等待,這樣一來就造成了永久等待,也就是線程死鎖。
?
本章內(nèi)容到此結(jié)束,由于時間倉庫,本文或許有很多不盡人意的地方,希望各位能夠理解和體諒。最后祝愿大家,在新的一年事事順心,萬事如意,羊年行大運。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
