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

