一、subprocess模塊 os.system 輸出命令結果到屏幕,返回命令執行狀態 使用方式為: res=os.system('dir') 結果顯示為: 結果顯示為: 驅動器 C 中的捲是 WINDOWS 捲的序列號是 CC81-05A6 C:\Users\zhao 的目錄 2017/07/12 ...
一、subprocess模塊
os.system 輸出命令結果到屏幕,返回命令執行狀態 使用方式為:res=os.system('dir')
結果顯示為:
驅動器 C 中的捲是 WINDOWS 捲的序列號是 CC81-05A6 C:\Users\zhao 的目錄 2017/07/12 00:04 <DIR> . 2017/07/12 00:04 <DIR> .. 2017/05/15 01:33 <DIR> .android 2016/12/23 00:17 <DIR> .idlerc 2017/03/11 13:39 <DIR> .oracle_jre_usage 2017/04/08 20:04 352 .packettracer 2017/02/13 22:01 <DIR> .PyCharm50 2017/07/12 00:32 <DIR> .THypervBox 2017/06/23 05:57 <DIR> .VirtualBox 3 個文件 352 位元組 9 個目錄 50,369,916,928 可用位元組再次列印res:
print(res)
結果為:
0 即發現,os.system()只及時執行,而不會將結果存儲下來。 如果既想要輸出命令的結果,又想要輸出命令的執行狀態 1、可以使用popenimport os res=os.popen("dir").read() print(res)
2、可以使用subprocess
先介紹下run命令:
run命令: shell=True 在subprocess.run()中使用,其意思為無需python進行代碼解釋。其使用的 主體結構為 : subprocess.run(“需要執行的命令 ”,shell=True)。若使用了shell=true,則需要執行的命令處:可以直接使用 df -h。不使用的話則需將命令拆開,設置 為“df","-h".若存在管道符,則其輸入格式直接使用“df -h | grep ***”,即為將所有參數合為一。 例如:import subprocess subprocess.run("dir",shell=True)
此命令僅支持直接輸出命令結果
call命令:
subprocess.call() 返回執行命令的狀態 狀態為0或者非0.類似os.system() subprocess.check_call()命令執行正常則返回結果,如果不正常則直接報錯,即運行出現錯誤。 舉例如:import subprocess res=subprocess.call("dir",shell=True) print(res)
最終若執行成功,res==0 執行不成功 res==1且報錯
check_call()
import subprocess res=subprocess.check_call("dirsfsf",shell=True) print(res)
運行即會報錯
getstatusoutput(): subprocess.getstatusoutput() 執行命令,並返回執行是否成功和執行結果。 res=subprocess.getstatusoutput("ipconfig") print(res[0]) [0]為執行是否成功,0為成功,1為失敗。 print(res[1]) [1]為執行命令的結果。即在系統中輸入ipconfig後出現的輸出。import subprocess res=subprocess.getstatusoutput("ipconfig") print(res[0]) print(res[1])
結果為
Popen() 如果想要將結果存儲下來,那麼需要這樣使用:
res=subprocess.Popen("ipconfig",shell=True,stdout=subprocess.PIPE) print(res.stdout.read())stdout 為標準輸出 此種輸出有三類: stdout 為標準輸出 stdint 為標準輸入 stderr為標準錯誤。 若執行的命令執行時間過長,則結果需要等待執行完成。 比如此類代碼,執行需要時間,那麼我們可以添加res.wait()#等到結果,然後返回。
res=subprocess.Popen("sleep 10;echo 'hello'",shell=True,stdout=subprocess.PIPE,stderr=subproess.PIPE) res.poll() print(res.poll()) #返回None則為還未出結果,返回0則表示結果已經出來了。
res.wait()#等到結果,然後返回。
terminate()殺死任務進程,使用方式如下:res.terminate() subprocess.Popen()可調用的參數: args:shell命令,可以是字元串或者序列類型 bufsize:指定緩衝。 stdin,stdout,stderr。 close_sfs 在Windows平臺系,如果close_fds被設置為True,則新創建的子進程將不會繼承父進程的輸入、輸出、錯誤管道。所以不能將close_sfs設置為True同時重定向子進程的標準輸入、輸出、與錯誤。 cwd:用於設置子進程的當前目錄。 env:用於指定子進程的環境變數。如果env=None,子進程的環境變數將從父進程繼承。 universal_newlines:不同系統的換行符不同, 為True則同意使用\n startupinfo與createionflags只在windows下有效。將被傳遞給底層的CreateProcess()函數,用於設置子進程的一些屬性,如:主視窗的外觀,進程的優先順序等等
二、面向對象
OOP Object Oriented programing 面向對象編程 是利用“類”和“對象”來創建各種模型來實現對真是世界的描述。 之前定義的函數主要涉及的是功能的實現。即將一個能夠完成某一動作的代碼封存到一塊,誰用誰來取即可。而類則僅僅是提供了同一類事物中,某一方面存在統一特性的一個模板。若需要對其使用,則要進行一個實例化操作,之後才可以執行該類事物擁有的相關功能。 舉一個例子: 我們拿開車這個技能來做一個說明。在沒接觸面向對象之前,我們會將開車這項技能寫成一個函數,然後讓會開車的人調用此功能,不會開車的人就不調用此功能。或者是進行一個判斷,輸出對應的開車技能。類似如下方式:# -*- coding:utf-8 -*- def driver(name,age,gender,skill): if skill=="會": if int(age)>=35: msg="%s,性別%s,今年%s歲,開車穩。"%(name,gender,age) else: msg="%s,性別%s,今年%s歲,開車毛躁。"%(name,gender,age) elif skill=="不會": msg="%s,性別%s,今年%s歲,不會開車。"%(name,gender,age) return msg zhangsan=driver("zhangsan",35,"male","不會") print(zhangsan)
通過函數,我們判斷出了這個人到底會不會開車,有沒有這項技能,算是完成了任務。但是現在突然又來了一個需求,要判斷這個人會不會游泳。這跟剛剛的需求完全不搭邊。那我們也可以再寫一個函數完成這個工作:
# -*- coding:utf-8 -*- def driver(name,age,gender,skill_drive): if skill_drive=="會": if int(age)>=35: msg="%s,性別%s,今年%s歲,開車穩。"%(name,gender,age) else: msg="%s,性別%s,今年%s歲,開車毛躁。"%(name,gender,age) elif skill_drive=="不會": msg="%s,性別%s,今年%s歲,不會開車。"%(name,gender,age) return msg def swimming(name,age,gender,skill_swim): if skill_swim=="會": msg="%s,性別%s,今年%s歲,游泳很6。"%(name,gender,age) elif skill_swim=="不會": msg="%s,性別%s,今年%s歲,不知道啥是游泳。"%(name,gender,age) return msg zhangsan=driver("zhangsan",35,"male","不會") zhangsan2=swimming("zhangsan",35,"male","不會") print(zhangsan) print(zhangsan2)而從面向對象的角度來看,我們當前涉及到的對象皆為人,並且我們只涉及到了人的技能方面,那麼就從我們的應用出發,只做技能信息。從而在面向對象的角度上分析可得: 1、基類是人,都會有姓名、年齡、性別等屬性 2、有人存在開車這項技能,可以通過駕駛車輛到達自己的目的地。 3、有人不會開車,只能通過腿著到達自己的目的地。 順著這樣的情況思考下來,基本上就體現了面向對象的思考方式。 而體現到代碼上,則是如下方式:
# -*- coding:utf-8 -*- class Person(): def __init__(self,name,age,gender): self.NAME=name self.AGE=age self.GENDER=gender class Skill(Person): def __init__(self,name,age,gender,skill_driver,skill_swimming): Person.__init__(self,name,age,gender) self.drivers=skill_driver self.swim=skill_swimming def driver(self): if self.drivers=="會": if int(self.AGE)>=35: msg="%s,性別%s,今年%s歲,開車穩。"%(self.NAME,self.GENDER,self.AGE) else: msg="%s,性別%s,今年%s歲,開車毛躁。"%(self.NAME,self.GENDER,self.AGE) elif self.drivers=="不會": msg="%s,性別%s,今年%s歲,不會開車。"%(self.NAME,self.GENDER,self.AGE) return msg def swimming(self): if self.swim=="會": msg="%s,性別%s,今年%s歲,游泳很6。"%(self.NAME,self.GENDER,self.AGE) elif self.swim=="不會": msg="%s,性別%s,今年%s歲,不知道啥是游泳。"%(self.NAME,self.GENDER,self.AGE) return msg zhangsan=Skill("zhangsan",30,"male","會","會") print(zhangsan.driver()) print(zhangsan.swimming())以上是在思路上介紹的面向對象,下麵是在語法上介紹下代碼結構: class為創建類的關鍵詞,表示創建的此項內容為類 def __init__(self,name,age,gender)構造函數,或者叫構造方法。代表的是傳入的參數,而self可以理解為是類中連通內部各函數,方便調用傳入參數的某項功能。self預設自動填寫,而self.NAME=name則是將傳入的name賦值給了self.NAME,保證了在類內部的通行。 而self._name則代表了私有屬性,表示外部無法訪問到此屬性。
def driver()就是正常的函數了,此函數只會在最終調用時,與原來的函數有些區別,其調用的方式需要先加上類名。類中再次設置函數是為了區分各項功能,同時也做到了實例化以後所有功能不自動運行。 部分私有屬性外部想要訪問,但是不允許改動的情況下,可以定義一個方法,僅返回私有屬性,不做其他操作。如:
def get_NAME(self):#對外提供只讀訪問介面。 return self._Name
若需強制訪問私有屬性,則可進行如下操作:實例化對象._所在類名+私有屬性 如 a.Person__talk __talk為私有屬性
在類中直接定義的屬性即為公有屬性。 如:class Person: gender="Male" def __init__(self,name,age): self.NAME=name self.age=AGE
其中,gender即為公有屬性。 若調用Person更改gender,則全局都會改變,若調用某一實例化對象更改gender,則只會更改這一實例化對象的gender。 如 Person.gender=“Female"會更改全局 而 a= Person() a.gender="Female" 則改了自身的屬性。 對於類中的函數,也是類似構造函數一樣,若需要更改單獨實例的類內函數,需要單獨進行重寫,調用的時候調用單獨重寫的函數才可以。 析構方法:只要引用被清空的時候,就會執行。 析構函數的形式: def __del__(self): pass 應用場景,客戶端與服務端正在正常連接,目前服務端要例行維護,需要停止,但此時客戶端仍舊正常連接著,為了在服務端停止以後不出現異常,可以在服務端的析構函數中寫入關閉所有客戶端連接。做一些程式的收尾工作。 繼承 子類繼承父類的構造函數,同時若需要,也可以先繼承,再重構。 類名開頭大寫,函數不需要開頭大寫。 如何列印實例中所有的數值: 1、首先,可以直接在子類中寫一個列印。 2、可以直接在父類中使用self.__dict__來進行迴圈取值。 多態: 多態是允許將子類類型的指針賦值給父類類型的指針 如以下形式:
class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("%s is talking"%self.name) class Child(Person): def __init__(self,name,age,gender): super(Child, self).__init__(name,age,gender) def talk(self): print("%s is child"%self.name) class Adult(Person): def __init__(self,name,age,gender): super(Adult, self).__init__(name,age,gender) def talk(self): print("%s is adult"%self.name)#此處定義的函數,是獨立於類之外的,即為了實現多態,重新定義了一個新的類,讓其能夠滿足一個介面,多種形態。
def talk(obj): obj.talk()d=Child("liu",10,"male") e=Adult("lu",26,"male") 靜態方法 在方法前面直接冠 @staticmethod 這樣寫完以後,方法實際上跟類沒什麼關係了。相當於跟類的關係截斷了。 只是名義上歸類管理,實際上在靜態方法里訪問不了類或實例中的任何屬性。 類方法: 只能訪問類變數,不能訪問實例變數
class Person(): name="li" def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender #若在前加@classmethod,則只能使用全局下的name,而不能使用構造函數中的self.name @classmethod def talk(self): print("%s is talking"%self.name)
d=Person("liu",25,"male")
d.talk()
#此為最終結果
res:
li is talking
若將代碼talk部分改為: @classmethod def talk(self): print("%s is talking"%self.age) 則代碼就會出現問題,提示找不到age屬性屬性方法:把一個方法變為靜態屬性,形式為@property.
class Person(): name="li" def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender @property def talk(self): print("%s is talking"%self.name)#加上@property之後,改方法就變成了一個靜態屬性,不是一個方法了,而在調用的時候,就不需要再加括弧了。 直接如下調用即可: d= Person("liu",26,"male") d.talk
屬性方法如果需要傳入值,則需要用到.setter裝飾器再裝飾一下。如:
def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender @property def talk(self): print("talking") @talk.setter def talk(self,owner): print("%s is talking"%owner) d=Person("liu",26,"male") d.talk="liu"
結果為 : liu is talking
類的特殊成員方法: __doc__ 列印這個類的描述信息
class Person(): __doc__ = "這個類是用來定義基類:人 的" def __init__(self,name,age): self.name=name self.age=age def talking(self): print("% is talking"%self.name) a=Person("liu",25) print(a.__doc__)__moudile__ 和__class__ __moudle__ 表示當前操作的對象在哪個模塊中 __class__ 表示當前操作的對象的類是什麼 __init__構造方法 __del__析構方法,當對象在記憶體中被釋放時,自動觸發執行。
res:
直接輸出: 這個類是用來定義基類:人 的
__call__ 對象後面加括弧,觸發執行 舉例如下:
class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("%s is talking"%self.name) def __call__(self, *args, **kwargs): print("this is %s call"%self.name) d=Person("liu",26,"male") d() 結果為
this is liu call
class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("talking") d=Person("liu",26,"male") print(d.__dict__) print(Person.__dict__)類.__dict__ 列印類里的所有屬性,不包括實例屬性 實例.__dict__列印所有實例屬性,不包括類里的屬性
__str__如果一個類中定義了__str__方法,那麼在列印對象時,預設輸出該方法的返回值。 舉例如下 class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("talking") def __str__(self): print("此為str方法") return “No” d=Person("liu",26,"male") print(d) 結果為
此為str方法
No
PS.經過測試發現 __str__若返回的不是string,則會報錯,直接提示:TypeError: __str__ returned non-string ,因此設置時需要註意。
__getitem__、__setitem__、__delitem__ 用於索引操作,如字典。以上分別表示獲取、設置、刪除數據 首先是getitem
class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("talking") def __getitem__(self, item): print("此為getitem") if item=="key": return 3 elif item=="key2": return 6 elif item=="key3": return 9 else: return 12 d=Person("liu",26,"male") res=d.__getitem__("key") print(res) 結果為可更改res=d.__getitem__("key")來查看其它的值
此為getitem
3
然後是setitem class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("talking") def __setitem__(self, key, value): print("此為setitem") if key=="name": self.name=value elif key=="age": self.age=value elif key=="gender": self.gender=value d=Person("liu",26,"male") print(d.name) d["name"]="zhao" print(d.name)
結果為:
liu
此為setitem
zhao
最後是delitem: class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("talking") def __delitem__(self): print("此為del") del self.name d=Person("liu",26,"male") print(d.name) del d.name print(d.name) 將名稱刪除以後再次列印,結果即為以下內容:
liu
直接報錯
若對最終列印結果進行異常處理,將代碼改為: try: print(d.name) except AttributeError: print("屬性已被刪除") 則結果會變為:
liu
屬性已被刪除
__new__ \ __metaclass__
class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print("talking") d=Person("liu",26,"male") print(type(d)) print(type(Person))在以上函數中,d通過Person成為實例化對象,在此,d跟Person其實都是一個實例。 通過列印d 和Person的類型來看,二者都是通過類來創建的。 Person即為通過type的構造方法創建的。 從以上可知,類也可使用如下方式進行創建:
def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def talk(self): print(" %s is talking"%self.name) def eat(self): print("%s is eat, he/she is %s"%(self.name,self.age)) Person=type("Person",(object,),{"talk":talk,"__init__":__init__}) d=Person("liu",25,"male") d.talk()
所有函數在Person=type()之前都沒有關聯,但是在type之後就被關聯到了一塊
最終結果為:
liu is talking
而類預設是type類實例化產生的,type類中如何實現創建類,類又是如何創建對象的呢? 此處藉助alex的解釋來補充此部分: 答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化創建,所以,我們可以為 __metaclass__ 設置一個type類的派生類,從而查看 類 創建的過程。 類的生成 調用 順序依次是 __new__ --> __init__ --> __call__ metaclass 詳解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那個答案寫的非常好
三 面向對象進階
1、應用場景 什麼時候適用面向對象? 1、如果多個函數須傳入多個共同的參數時 2、根據一個模板創建某些東西 3、傳入值相同,需多次傳入的情況時 2、經典類和新式類 1、兩者寫法不同 經典類的寫法是class A: pass
新式類的寫法是
class A(object): pass2、繼承關係不同 新式類採用的是廣度優先搜索,經典類採用的是深度優先搜索。 python2.X中,預設採用的是經典類,只有顯式繼承了object的才是新式類 python3.X中,預設採用的都是新式類,不必顯式的繼承object 3、繼承傳參不同 新式類繼承時傳參可以使用super關鍵字
# -*- coding:utf-8 -*- class Person(): def __init__(self,name,age,gender): self.name=name self.age=age self.gender=gender def jieshao(self): print("I am %s"%self.name) class DaPerson(Person): def __init__(self,name,age,gender): # super(DaPerson, self).__init__(name,age,gender) 新式類的寫法 # Person.__init__(self,name,age,gender) 經典類的寫法,只是在此出現不一樣 def jieshao(self): print("I am DaPerson,name is %s"%self.name) zhangsan=DaPerson("zhangsan",22,"male") zhangsan.jieshao()3、self就是調用當前方法的對象。 創建的對象內部存在類對象指針。指向類內部的方法,在執行類內部方法時,也會把自己傳入到類中。 全局的屬性稱為靜態欄位 每個對象都存在一個公共的值的情況下,就可以將此值設置為靜態欄位。 而類對應生成的對象中,存在欄位主要是普通欄位或者說是普通屬性,共有欄位或者說是共有屬性是存放在類自身裡面的 方法: 普通方法(保存在類中,調用者對象,至少有一個self參數) 靜態方法: (可以有任意個參數,但python不會強制賦值self) class F1: @staticmethod def a1(): print('alex') 調用靜態方法可以直接調用: F1.a1() 後續socket與下章筆記一塊整理。