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

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