日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python进阶到高阶大全(强烈推荐)

發(fā)布時(shí)間:2023/12/20 python 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python进阶到高阶大全(强烈推荐) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

關(guān)鍵字is 和 == 的區(qū)別

a = 'hello world' b = 'hello world' a == b #返回True a is b #返回False

注意:is 判斷是否是一個(gè)ID, == 判斷內(nèi)容是否一致。

深拷貝和淺拷貝

import copy a = [1,2,3,4,5] b = a #淺拷貝,a,b同時(shí)指向一個(gè)id,當(dāng)其中一個(gè)修改時(shí),另外一個(gè)也會(huì)被修改。 c = copy.deepcopy(a) #深拷貝,c單獨(dú)開(kāi)辟一個(gè)id,用來(lái)存儲(chǔ)和a一樣的內(nèi)容。 d =a[:] #這樣也是深拷貝。 e = copy.copy(a) #當(dāng)拷貝內(nèi)容是可變類型時(shí),那么就會(huì)進(jìn)行深拷貝,如果是不可變類型時(shí),那么就會(huì)進(jìn)行淺拷貝。

注意:深拷貝指的是復(fù)制內(nèi)容,單獨(dú)開(kāi)辟一個(gè)內(nèi)存,淺拷貝指的是兩個(gè)變量同時(shí)指向一個(gè)內(nèi)存ID。
私有化和Property

class Test(object):def __init__(self):self.__num = 100@getNum.setter #等同步于 porperty(setNum,getNum)def setNum(self,num): #將self.__num的屬性封裝。self.__num = num@porperty #等于getNum = porperty(getNum) 默認(rèn)的是getter方法。def getNum(self) #獲取__num的值。return self.__numnum = porperty(getNum,setNum) #使用關(guān)鍵字porperty將getNum和setNum方法打包使用,并將引用賦予屬性num。 t = Test() print(t.__num) #將會(huì)出錯(cuò),表示輸出私有屬性,外部無(wú)法使用。 t.__num = 200 #這里將會(huì)理解為添加屬性 __num = 200,而不是重新賦值私有屬性。 print(t.__num) #這里輸出的200是定義的屬性__num,而不是self.__num。 t.setNum(200) #通過(guò)set方法將私有屬性重新賦值。 t.getNum() #通過(guò)get方法獲取__num的值。 print(_Test__num) #私有屬性其實(shí)是系統(tǒng)再私有屬性前加上了一個(gè)_Test,就是一個(gè)下劃線加類名。t.num = 300 #調(diào)用類屬性num,并重新賦值,porperty會(huì)自動(dòng)檢測(cè)set方法和get方法,并將引用賦值給set方法。 print(t.num) #輸出類屬性,并會(huì)自己檢測(cè)使用get方法進(jìn)行輸出。

注意: num 前后沒(méi)有下劃線的是公有方法,_num 前邊有一個(gè)下劃線的為私有方法或?qū)傩?#xff0c;子類無(wú)法繼承, 前邊有兩個(gè)下劃線的 一般是為了避免于子類屬性或者方法名沖突,無(wú)法在外部直接訪問(wèn)。前后都有雙下劃線的為系統(tǒng)方法或?qū)傩浴:筮厗蝹€(gè)下劃線的可以避免與系統(tǒng)關(guān)鍵詞沖突。

列表生成式

range(1,100,5) #第一個(gè)參數(shù)表示開(kāi)始位,第二個(gè)參數(shù)表示結(jié)束位(不含),第三個(gè)參數(shù)表示步長(zhǎng),就是每5個(gè)數(shù)返回一次。 a = [i for i in range(1,10)] #列表生成式表示返回i的值,并且返回9次,每次返回的是i的值。 a = [2 for i in range(1,10)] #這里表示返回2,并且返回9次,但是每次的值都是2。 a = [i for i in range10 if i%2==0] #表示在生成式內(nèi)部加入if判斷,當(dāng)i除以2的余數(shù)等于0的時(shí)候?qū)?shù)值返回。 a = [(i,j) for i in range(5) for j in range(5)] #表示將i和j的值以元組為元素的形式返回,當(dāng)i循環(huán)一次的時(shí)候j循環(huán)5次,以此類推。

生成器

a = (i for i in range(1,10)) #將列表生成試外部的中括號(hào)改為小括號(hào),就能將生成式轉(zhuǎn)化為生成器。 next(a),a.__next__() #生成器的取值方式只能使用next的方法。 def num():a,b = 0,1for i in range(10):yield b #生成關(guān)鍵字yield,有yield的關(guān)鍵字的代碼塊就是yield的生成器。當(dāng)運(yùn)行到y(tǒng)ield時(shí)代碼就會(huì)停止,并返回運(yùn)行結(jié)果,當(dāng)在次運(yùn)行時(shí)依舊是到y(tǒng)ield停止,并返回結(jié)果。 切記:生成器只能使用next方法。a,b = b,a+btemp = yield b #這里并不是變量的定義,當(dāng)運(yùn)行到y(tǒng)ield時(shí)就會(huì)停止,所以當(dāng)運(yùn)行到等號(hào)右邊的時(shí)候就會(huì)停止運(yùn)行,當(dāng)在次使用next的時(shí)候,將會(huì)把一個(gè)None賦值給temp,因?yàn)閎的值已經(jīng)在上輪循環(huán)中輸出。這里可以使用num().send()方法將一個(gè)新的值賦值給temp。 a = num() #將生成器賦值給變量a。 for n in a: #生成器可以使用for循環(huán)使用,并且不會(huì)出錯(cuò)。print(n)

注意:生成器占用內(nèi)存小,在使用的時(shí)候取值,降低CPU和內(nèi)存空間,提高效率。并且一般都使用for循環(huán)進(jìn)行取值。

迭代器

for i in '',[],(),{},{:} #可以for循環(huán)的對(duì)象是可迭代對(duì)象。 a = (x for i in range(100)) #列表生成式,把中括號(hào)改為小括號(hào)就可以變?yōu)橐粋€(gè)列表生成器,是可迭代對(duì)象。 from collections import Iterable #如果想驗(yàn)證是否是可迭代對(duì)象,可以使用isinstance()判斷是否是可迭代對(duì)象。 isinstance('abc',Ierable) #判斷語(yǔ)法 a = [1,2,3,4,5] b = iter(a) #使用iter()方法可以將可迭代對(duì)象轉(zhuǎn)換為可迭代對(duì)象。

注意:生成器是可迭代對(duì)象,迭代器不一定是生成器。并且迭代器無(wú)法回取,只能向前取值。
注意:一個(gè)對(duì)象具有 iter 方法的才能稱為可迭代對(duì)象,使用yield生成的迭代器函數(shù),也有iter方法。凡是沒(méi)有iter方法的對(duì)象不是可迭代對(duì)象,凡是沒(méi)有__next__()方法的不是是生成器。(這里的方法都是魔法方法,是內(nèi)置方法,可以使用dir()查看)

閉包

def num(num): #定義函數(shù)def num_in(nim_in): #定義函數(shù)return num + num_in #返回兩個(gè)參數(shù)的和。return num_in #返回內(nèi)部函數(shù)的引用。(變量名)a = num(100) #將參數(shù)為100的函數(shù)num接收,并賦值給a,只不過(guò)這個(gè)返回值是一個(gè)函數(shù)的引用。等于 a = num_in,注意這里接收的不光是函數(shù)本身,還有已經(jīng)傳遞的參數(shù)。 b = a(100) #調(diào)用函數(shù)a,即num_in,并傳遞一個(gè)參數(shù)100,返回值給b。

注意:當(dāng)一個(gè)函數(shù)定義在另一個(gè)函數(shù)內(nèi),且使用到了外部函數(shù)的參數(shù)。整個(gè)代碼塊稱為閉包。當(dāng)外部參數(shù)確定時(shí),內(nèi)部函數(shù)參數(shù)可以反復(fù)調(diào)用。

裝飾器

裝飾沒(méi)有參數(shù)的函數(shù)

def function(func): #定義了一個(gè)閉包def func_in(): #閉包內(nèi)的函數(shù)print('這里是需要裝飾的內(nèi)容,就是需要添加的內(nèi)容')func() #調(diào)用實(shí)參函數(shù)。return func_indef test(): #需要被裝飾修改的函數(shù)。print('無(wú)參函數(shù)的測(cè)試')test = function(test) #裝飾器的原理就是將原有的函數(shù)名重新定義為以原函數(shù)為參數(shù)的閉包。 test() 這里再次掉用test()的時(shí)候,其實(shí)是將會(huì)調(diào)用閉包內(nèi)的函數(shù)func_in()。所以將會(huì)起到裝飾修改的作用,最后會(huì)再次調(diào)用原函數(shù)test()。@function #裝飾器的python寫法,等價(jià)于test = function(test),并且無(wú)需調(diào)用當(dāng)代碼運(yùn)行道這里,Python會(huì)自動(dòng)運(yùn)行。 def test():print('無(wú)參函數(shù)的測(cè)試') test() #這里再次調(diào)用函數(shù)時(shí),將會(huì)產(chǎn)生修改后的效果。

裝飾帶有參數(shù)的函數(shù)

def function(func): #定義了一個(gè)閉包def func_in(*args,**kwargs): #閉包內(nèi)的函數(shù),因?yàn)檠b飾器運(yùn)行的實(shí)則是閉包內(nèi)的函數(shù),所以這里將需要有形參用來(lái)接收原函數(shù)的參數(shù)。print('這里是需要裝飾的內(nèi)容,就是需要添加的內(nèi)容')func(*args,**kwargs) #調(diào)用實(shí)參函數(shù),并傳入一致的實(shí)參。return func_in@function #裝飾器的python寫法,等價(jià)于test = function(test) . def test():print('無(wú)參函數(shù)的測(cè)試')test(5,6) #這里再次掉用test()的時(shí)候,其實(shí)是將會(huì)調(diào)用閉包內(nèi)的函數(shù)func_in()。所以將會(huì)起到裝飾修改的作用,最后會(huì)再次調(diào)用原函數(shù)test()。

裝飾帶有返回值的函數(shù)

def function(func): #定義了一個(gè)閉包def func_in(*args,**kwargs): #閉包內(nèi)的函數(shù),因?yàn)檠b飾器運(yùn)行的實(shí)則是閉包內(nèi)的函數(shù),所以這里將需要有形參用來(lái)接收原函數(shù)的參數(shù)。print('這里是需要裝飾的內(nèi)容,就是需要添加的內(nèi)容')num = func(*args,**kwargs) #調(diào)用實(shí)參函數(shù),并傳入一致的實(shí)參,并且用變量來(lái)接收原函數(shù)的返回值,return num #將接受到的返回值再次返回到新的test()函數(shù)中。return func_in @function def test(a,b): #定義一個(gè)函數(shù)return a+b #返回實(shí)參的和

通用裝飾器

def function(func): #定義了一個(gè)閉包def func_in(*args,**kwargs): #閉包內(nèi)的函數(shù),因?yàn)檠b飾器運(yùn)行的實(shí)則是閉包內(nèi)的函數(shù),所以這里將需要有形參用來(lái)接收原函數(shù)的參數(shù)。print('這里是需要裝飾的內(nèi)容,就是需要添加的內(nèi)容')num = func(*args,**kwargs) #調(diào)用實(shí)參函數(shù),并傳入一致的實(shí)參,并且用變量來(lái)接收原函數(shù)的返回值,return num #將接受到的返回值再次返回到新的test()函數(shù)中。return func_in

帶有參數(shù)的裝飾器

def func(*args,**kwags):def function(func): #定義了一個(gè)閉包def func_in(*args,**kwargs): #閉包內(nèi)的函數(shù),因?yàn)檠b飾器運(yùn)行的實(shí)則是閉包內(nèi)的函數(shù),所以這里將需要有形參用來(lái)接收原函數(shù)的參數(shù)。print('這里是需要裝飾的內(nèi)容,就是需要添加的內(nèi)容')num = func(*args,**kwargs) #調(diào)用實(shí)參函數(shù),并傳入一致的實(shí)參,并且用變量來(lái)接收原函數(shù)的返回值,return num #將接受到的返回值再次返回到新的test()函數(shù)中。return func_inreturn function@func(50) #這里會(huì)先運(yùn)行函數(shù)func,并切傳入?yún)?shù),之后會(huì)再次運(yùn)行閉包函數(shù)進(jìn)行裝飾, @func(50)>>@function,然后將由@function繼續(xù)進(jìn)行裝飾修改。 def test(a,b):print('這是一個(gè)函數(shù)')return a+b
  • ?
class Test(object): #定義一個(gè)類def __init__(self,func):self.__func = funcdef __call__(self): #定義call方法,當(dāng)直接調(diào)用類的時(shí)候,運(yùn)行這里。print('這里是裝飾的功能')self.__func() t = Test() #實(shí)例化對(duì)象 t() #調(diào)用類,將會(huì)調(diào)用call方法。@Test #類裝飾器等于test = Test(test),將函數(shù)test當(dāng)作參數(shù)傳入類中的init方法,并將函數(shù)名賦值給私有屬性__func,當(dāng)函數(shù)test被調(diào)用的時(shí)候,其實(shí)是運(yùn)行Test類中的call方法. def test():print('被裝飾的函數(shù)') test() #這里調(diào)用的不在是函數(shù)test,而是實(shí)例對(duì)象test的call方法,會(huì)先進(jìn)行裝飾,然后再調(diào)用私有屬性__func(),__func 其實(shí)就是被裝飾的函數(shù)test。

動(dòng)態(tài)語(yǔ)言添加屬性和方法

class Person(): #創(chuàng)建一個(gè)類def __init__(self,name): #定義初始化信息。self.name = name li = Person('李') #實(shí)例化Person('李'),給變量li li.age = 20 #再程序沒(méi)有停止下,將實(shí)例屬性age傳入。動(dòng)態(tài)語(yǔ)言的特點(diǎn)。 Person.age = None #這里使用類名來(lái)創(chuàng)建一個(gè)屬性age給類,默認(rèn)值是None。Python支持的動(dòng)態(tài)屬性添加。 def eat(self): #定義一個(gè)方法,不過(guò)這個(gè)方法再類之外。print('%s正在吃東西。。'%self.name) import types #動(dòng)態(tài)添加方法需要使用tpyes模塊。 li.eat = types.MethodType(eat,li) #使用types.MethodType,將函數(shù)名和實(shí)例對(duì)象傳入,進(jìn)行方法綁定。并且將結(jié)果返回給li.eat變量。實(shí)則是使用一個(gè)和li.eat方法一樣的變量名用來(lái)調(diào)用。 li.eat() #調(diào)用外部方法eat()方法。@staticmethod #定義靜態(tài)方法。 def test(): #定義靜態(tài)方法,靜態(tài)方法可以不用self參數(shù)。print('這是一個(gè)靜態(tài)方法。') Person.test = test #使用類名.方法名 = test的形式來(lái)方便記憶和使用,Person.test其實(shí)只是一個(gè)變量名,沒(méi)有特殊的含義。 Person.test() #調(diào)用test方法。@classmethod #類方法 def test(cls): print('這是一個(gè)類方法。') Person.test = test #定義一個(gè)類屬性等于方法名。 Person.test() #調(diào)用方法。class test(object): #定義一個(gè)類。__slots__ = ('name','age') #使用slots來(lái)將屬性固定,不能進(jìn)行動(dòng)態(tài)添加修改。

元類

創(chuàng)建帶有類屬性的類

Test = type('Test',(object,),{'num':0} #元類是只使用type創(chuàng)建的類,使用type會(huì)有3個(gè)參數(shù),第一個(gè)是類名,第二個(gè)小括號(hào)內(nèi)是父類名,需要使用元組。第三個(gè)字典中是類屬性,使用type能夠快速的動(dòng)態(tài)創(chuàng)建一個(gè)類。 class Test(object): #創(chuàng)建一個(gè)類,等價(jià)于上邊num = 0

創(chuàng)建帶有方法的類

def eat(self): #定義一個(gè)函數(shù),self作為第一個(gè)參數(shù)。print ('%s正在吃飯。。'%self.name) Person = type('Person',(object,), {'eat':eat,'name':None} #使用type創(chuàng)建一個(gè)類,但是有兩個(gè)屬性,一個(gè)是eat,一個(gè)是name,但是eat的值是函數(shù)eat的引用。 p = Person() #實(shí)例化 p.name = 'Tom' #類屬性賦值 p.eat() #調(diào)用eat()方法。

內(nèi)建屬性

__init__ #構(gòu)造初始化函數(shù),__new__之后運(yùn)行 __new__ #創(chuàng)建實(shí)例所需的屬性 __class__ #實(shí)例所在的類,實(shí)例.__class__ __str__ #實(shí)例的字符串表示,可讀性高 __repr__ #實(shí)例的字符串表示,準(zhǔn)確性高 __del__ #刪除實(shí)例引用 __dict__ #實(shí)力自定義屬性,vars(實(shí)例.__dict__) __doc__ #類文檔,help(類或者實(shí)例) __bases__ #當(dāng)前類的所有父類 __getattribute__ #屬性訪問(wèn)攔截器。

內(nèi)建方法

range(start,stop,[,step]) #生成器 map(function, iterable, ...) # map() 會(huì)根據(jù)提供的函數(shù)對(duì)指定序列做映射。 filter(function, iterable) #filter() 函數(shù)用于過(guò)濾序列,過(guò)濾掉不符合條件的元素,返回由符合條件元素組成的新列表。 reduce(function, iterable[, initializer]) #reduce() 函數(shù)會(huì)對(duì)參數(shù)序列中元素進(jìn)行累積。 sorted(iterable[, cmp[, key[, reverse]]]) #sorted() 函數(shù)對(duì)所有可迭代的對(duì)象進(jìn)行排序操作。sort 與 sorted 區(qū)別: sort 是應(yīng)用在 list 上的方法,sorted 可以對(duì)所有可迭代的對(duì)象進(jìn)行排序操作。 list 的 sort 方法返回的是對(duì)已經(jīng)存在的列表進(jìn)行操作,而內(nèi)建函數(shù) sorted 方法返回的是一個(gè)新的 list,而不是在原來(lái)的基礎(chǔ)上進(jìn)行的操作。

PDB調(diào)試

1.python -m pdb xxx.py #在命令行輸入以上命令,進(jìn)入pdb調(diào)試模式。XXX.py表示需要打開(kāi)的文件。 2.import pdb pdb.run('func(*args)') #第二種方式,當(dāng)程序在運(yùn)行中調(diào)試。 3.pdb.set_trace() #第三種方法,當(dāng)程序運(yùn)行到這行代碼時(shí),就會(huì)自動(dòng)運(yùn)行。 l(list) # 顯示全部代碼 n(next) # 向下執(zhí)行一行代碼 c(contiune) # 執(zhí)行余下的代碼 b(break) 10 # 設(shè)置斷點(diǎn),b 10表示將斷點(diǎn)設(shè)置到第10行。clear 1,刪除第一個(gè)斷點(diǎn) p(print) a,b #打印變量的值 a(args) #打印全部的形參數(shù)據(jù) s(step) #進(jìn)入到一個(gè)函數(shù) r(return) #快速執(zhí)行到函數(shù)的最后一行

進(jìn)程和線程

進(jìn)程

import os pid = os.fork() #這里將會(huì)創(chuàng)建一個(gè)子進(jìn)程,返回值會(huì)是子進(jìn)程PID值。 print('父子進(jìn)程都會(huì)輸出。') #這里沒(méi)有判斷語(yǔ)句,將會(huì)運(yùn)行兩次,一次是父進(jìn)程,一次是子進(jìn)程。 if pid > 0: #判斷,父進(jìn)程的返回值會(huì)大于0。print('子進(jìn)程的PID是%d,父進(jìn)程的PID是%d'%(os.getpid(),os.getppid())) #getpid的獲取當(dāng)前進(jìn)程的pid,如果子進(jìn)程getpid的時(shí)候,會(huì)得到子進(jìn)程的值,再子進(jìn)程使用getppid的時(shí)候能夠獲取到父進(jìn)程的pid。 else: #子進(jìn)程的返回值則會(huì)永遠(yuǎn)是0print('父進(jìn)程的PID是%d'%os.getpid()) #當(dāng)父進(jìn)程使用getpid的時(shí)候獲得的是父進(jìn)程的pid。

**注意:**進(jìn)程值PID是不能重復(fù)的,類似于端口。系統(tǒng)會(huì)為每個(gè)進(jìn)程會(huì)分配不同的PID進(jìn)行區(qū)分不同的軟件進(jìn)程。并且父子進(jìn)程會(huì)獨(dú)立運(yùn)行,互不干擾。而且父子進(jìn)程的調(diào)用需要系統(tǒng)來(lái)調(diào)度,沒(méi)有固定性。

import os pid = os.fork() #創(chuàng)建子進(jìn)程,接收pid的返回值。 if pid > 0: #判斷是子進(jìn)程還是父進(jìn)程。print('父進(jìn)程') #當(dāng)pid的返回值是0的時(shí)候,會(huì)運(yùn)行父進(jìn)程 else:print('子進(jìn)程') #否則就是子進(jìn)程 pid =os.fork() #讓之前的父子進(jìn)程再次創(chuàng)建各自的子進(jìn)程 if pid > 0: #判斷父子進(jìn)程print('父進(jìn)程的子進(jìn)程') #這里會(huì)運(yùn)行2次父進(jìn)程 else:print('子進(jìn)程的子進(jìn)程') #這里也會(huì)運(yùn)行兩次子進(jìn)程

windons中的fork()-Process

from multiprocessing import Process #導(dǎo)入模塊類,這是一個(gè)類 import time def test(): #定義一個(gè)函數(shù)while True:print('-1-')time.sleep(1) p = Process(target=test) #創(chuàng)建一個(gè)實(shí)例,就是一個(gè)新進(jìn)程,并且執(zhí)行的代碼就是test()函數(shù) p.start() #調(diào)用start方法讓子進(jìn)程開(kāi)始運(yùn)行。 p.join(10) #join表示延時(shí)時(shí)間,也就是等待子進(jìn)程的時(shí)間,當(dāng)10秒過(guò)了以后,則會(huì)運(yùn)行主進(jìn)程。 while True: #這里是主進(jìn)程。print('-2-')time.sleep(1)

注意:Process需要自己創(chuàng)建進(jìn)程,以及調(diào)用開(kāi)始進(jìn)程,fork則是全自動(dòng)運(yùn)行。后期最好以Process為主,可實(shí)現(xiàn)跨平臺(tái)運(yùn)行。還有最主要的一點(diǎn)是Process的主進(jìn)程會(huì)等待子進(jìn)程。

Process實(shí)例

from multiprocessing import Process import timeclass Process_class(Process): #創(chuàng)建一個(gè)Process的子類。def run(self): #重寫run方法,當(dāng)調(diào)用start方法時(shí),則會(huì)默認(rèn)調(diào)用run方法,所以不用再填寫target參數(shù)。while True:print('--1--')time.sleep(1) p = Process_class() #實(shí)例化一個(gè)子進(jìn)程。 p.start() #運(yùn)行子進(jìn)程 p.join(5) #這里將會(huì)等待子進(jìn)程單獨(dú)運(yùn)行5秒。 while True: #主進(jìn)程,當(dāng)join等待結(jié)束收,則會(huì)父子進(jìn)程一起運(yùn)行。但是如果當(dāng)父進(jìn)程運(yùn)行完,子進(jìn)程還沒(méi)有結(jié)束,那么父進(jìn)程會(huì)繼續(xù)等子進(jìn)程。print('--main--')time.sleep(1)

進(jìn)程池Pool

from multiprocessing import Pool #導(dǎo)入Pool模塊類 import os,time def work(num): #創(chuàng)建一個(gè)進(jìn)程的工作函數(shù)。for i in range(2): #表示每次工作需要執(zhí)行2次。print('進(jìn)程的pid是%d,進(jìn)程值是%d'%(os.getpid(),num)) #輸出兩次time.sleep(1)p = Pool(2) #實(shí)例化對(duì)象,參數(shù)2表示創(chuàng)建2個(gè)子進(jìn)程,就是說(shuō)每次只能執(zhí)行2個(gè)進(jìn)程。for i in range(6): print('--%d--'%i)p.apply_async(work,(i,)) #向?qū)嵗龑?duì)象添加6次任務(wù),就是6個(gè)進(jìn)程,但是實(shí)例對(duì)象的進(jìn)程池只有2個(gè),需要每次執(zhí)行2個(gè)進(jìn)程,當(dāng)2個(gè)進(jìn)程執(zhí)行完以后則會(huì)再次執(zhí)行下面2個(gè)。p.close() #關(guān)閉進(jìn)程池,不再接收進(jìn)程任務(wù)。 p.join() #當(dāng)子進(jìn)程工作結(jié)束后,則會(huì)運(yùn)行主進(jìn)程。

Queue隊(duì)列

Process的Queue用法

from multiprocessing import Process,Queue #導(dǎo)入Process和Queue import os,time,randomdef write(q): #定義函數(shù),接收Queue的實(shí)例參數(shù)for v in range(10):print('Put %s to Queue'%v)q.put(v) #添加數(shù)據(jù)到Queuetime.sleep(1) def read(q): #定義函數(shù),接收Queue的實(shí)例參數(shù)while True:if not q.empty(): #判斷,如果Queue不為空則進(jìn)行數(shù)據(jù)取出。v = q.get(True) #取出Queue中的數(shù)據(jù),并返回保存。print('Get %s from Queue'%v)time.sleep(1)else: #如果Queue內(nèi)沒(méi)有數(shù)據(jù)則退出。breakif __name__ == '__main__':q = Queue() #實(shí)例化Queue括號(hào)內(nèi)可選填,輸入數(shù)字表示有多少個(gè)存儲(chǔ)單位。以堵塞方式運(yùn)行。必須等里邊有空余位置時(shí),才能放入數(shù)據(jù),或者只能等里邊有數(shù)據(jù)時(shí)才能取出數(shù)據(jù),取不出數(shù)據(jù),或者存不進(jìn)數(shù)據(jù)的時(shí)候則會(huì)一直在等待狀態(tài)。pw = Process(target=write,args=(q,)) #實(shí)例化子進(jìn)程pw,用來(lái)執(zhí)行write函數(shù),注意這里的函數(shù)不帶括號(hào),只是傳遞引用,參數(shù)需要使用args參數(shù)以元組的方式進(jìn)行接收。pr = Process(target=read,args=(q,)) #實(shí)例化子進(jìn)程pr,用來(lái)執(zhí)行read函數(shù),注意這里的函數(shù)不帶括號(hào),只是傳遞引用,參數(shù)需要使用args參數(shù)以元組的方式進(jìn)行接收。pw.start() #開(kāi)始執(zhí)行pw。pr.start() #開(kāi)始執(zhí)行pr。pw.join() #等待pw結(jié)束pr.join() #等待pr結(jié)束print('Over') #主進(jìn)程結(jié)束

Pool的Queue用法

from multiprocessing import Manager,Pool #這里注意導(dǎo)入的是Manager和Pool import os,time,randomdef write(q):for v in range(10):print('Put %s to Queue'%v)q.put(v)time.sleep(1) def read(q):while True:if not q.empty():v = q.get(True)print('Get %s from Queue'%v)time.sleep(1)else:breakif __name__ == '__main__':q = Manager().Queue() #這里實(shí)例化的時(shí)候是使用Manager的Queuep = Pool()p.apply_async(write,(q,)) #將任務(wù)加入Pool的進(jìn)程池,注意這里的參數(shù)于Process不同。p.apply_async(read,(q,)) #將任務(wù)加入Pool的進(jìn)程池,注意這里的參數(shù)于Process不同。p.close() #關(guān)閉進(jìn)程池,不再接收進(jìn)程。p.join() #子進(jìn)程完畢,運(yùn)行以下的主進(jìn)程。print('Over')

線程

from threading import Thread #導(dǎo)入Thread線程類。 import timenum = 0 #定義全局變量def work(): #定義函數(shù)內(nèi)容global num for i in range(1000000):num += 1print('work的num是%d'%num)def works(): #定義函數(shù)global numfor i in range(1000000):num += 1print('works的num是%d'%num)t = Thread(target=work) #創(chuàng)建第一個(gè)線程內(nèi)置的self.name屬性為Thread-1,并指向work tt = Thread(target=works) #創(chuàng)建第二個(gè)線程內(nèi)置的self.name屬性為Thread-2,并指向works t.start() #開(kāi)始執(zhí)行 tt.start() #開(kāi)始執(zhí)行 time.sleep(1) #主線程休息一秒 print('最后的num值是%d'%num) #輸出最后的結(jié)果。

注意:線程中的變量數(shù)據(jù)是可以共享的,進(jìn)程與線程的區(qū)別在于,父子進(jìn)程是兩個(gè)單獨(dú)的個(gè)體,子進(jìn)程類似于直接拷貝的一份父進(jìn)程的代碼獨(dú)立運(yùn)行,相當(dāng)于兩個(gè)文件。線程則是再主進(jìn)程的內(nèi)部分裂運(yùn)行。舉例子來(lái)說(shuō)一個(gè)工廠需要做100萬(wàn)件衣服,但是工期太緊,自己做太慢,老板現(xiàn)在有兩個(gè)選擇,一個(gè)是雇傭另外一個(gè)同樣規(guī)模的工廠一起來(lái)做,兩個(gè)工廠一起做——進(jìn)程,另外一個(gè)選擇就是在自己的工廠內(nèi)大批量的招募工人用來(lái)趕工——線程。總得來(lái)說(shuō)線程的消耗成本會(huì)比進(jìn)程低很多。

互斥鎖

from threading import Thread,Lock #導(dǎo)入互斥鎖Locknum = 0def work():global numl.acquire() #這里表示調(diào)用互斥鎖上鎖方法,如果work函數(shù)先運(yùn)行l(wèi).acquire的話,那么后邊的程序就不能再修改和使用變量num。直到將其解鎖后才能使用。for i in range(1000000):num += 1print('work的num是%d'%num)l.release() #這里表示調(diào)用互斥鎖解鎖方法。def works():global numl.acquire() #這里表示調(diào)用互斥鎖上鎖方法。for i in range(1000000):num += 1print('works的num是%d'%num)l.release() #這里表示調(diào)用互斥鎖解鎖方法。l = Lock() #實(shí)例化互斥鎖,互斥鎖是為了保護(hù)子線程不爭(zhēng)搶數(shù)據(jù)而使用的一個(gè)類。 t = Thread(target=work) tt = Thread(target=works) t.start() tt.start() print('最后的num值是%d'%num) #輸出最后的結(jié)果,如果實(shí)驗(yàn)過(guò)的可能會(huì)發(fā)現(xiàn)這個(gè)結(jié)果并不是2000000,為什么呢? 這里需要明白,主線程和子線程是同時(shí)進(jìn)行的,因?yàn)閯?chuàng)建子進(jìn)程在前,最后輸出再后,所以當(dāng)最后線程輸出的時(shí)候,子線程還在運(yùn)行,也就是說(shuō)當(dāng)子線程的加法運(yùn)算加到95222的時(shí)候你的 主進(jìn)程剛好運(yùn)行到最后的輸出語(yǔ)句,所以就把95222拿過(guò)來(lái)進(jìn)行輸出。你也可以試試將最后的輸出語(yǔ)句放到實(shí)例化的前邊,看看結(jié)果是不是0,因?yàn)樽泳€程還沒(méi)有開(kāi)始工作,所以并沒(méi)有進(jìn)行加法運(yùn)算。

注意:因?yàn)榫€程的數(shù)據(jù)是共享數(shù)據(jù),不用Queue就能實(shí)現(xiàn),所以也會(huì)存在一些弊端,因?yàn)榫€程是在進(jìn)程間獨(dú)立運(yùn)行的,所以共享數(shù)據(jù)會(huì)有一定的延時(shí)性和不準(zhǔn)確性,舉例家里有10個(gè)饅頭,2個(gè)孩子,第一個(gè)孩子拿走一個(gè)會(huì)記得還剩下9個(gè),第二個(gè)孩子去拿的時(shí)候會(huì)記得還剩下8個(gè),但是當(dāng)?shù)谝粋€(gè)孩子再去拿的時(shí)候會(huì)發(fā)現(xiàn)只剩下7個(gè)了,但是之前明明還剩下9個(gè),這樣就會(huì)出現(xiàn)問(wèn)題。互斥鎖的作用就是再?gòu)N房裝上一把鎖,當(dāng)?shù)谝粋€(gè)孩子餓的時(shí)候就進(jìn)去吃饅頭,將門反鎖,這樣第二個(gè)孩子就吃不到再門口等著,當(dāng)?shù)谝粋€(gè)吃飽的時(shí)候第二個(gè)再進(jìn)去,也把門鎖上。這樣一個(gè)一個(gè)的來(lái)避免沖突。

同步、異步

import threading import timeclass MyThread(threading.Thread):def run(self):global num time.sleep(1)if mutex.acquire(1): num = num+1msg = self.name+' set num to '+str(num)print msgmutex.release() num = 0 mutex = threading.Lock() def test():for i in range(5):t = MyThread()t.start() if __name__ == '__main__':test()
  • ?
Thread-3 set num to 1 Thread-4 set num to 2 Thread-5 set num to 3 Thread-2 set num to 4 Thread-1 set num to 5
  • ?

注意:這里就是一個(gè)簡(jiǎn)單的同步,使用互斥鎖來(lái)實(shí)現(xiàn),因?yàn)槊總€(gè)線程在創(chuàng)建運(yùn)行的時(shí)候都是各自做各自的,如果沒(méi)有互斥鎖來(lái)約束步調(diào),那么結(jié)果是1,2,3,4,5的概率是未知數(shù),但是加上了互斥鎖以后,就會(huì)對(duì)線程的運(yùn)行順序進(jìn)行排隊(duì),達(dá)到預(yù)期的結(jié)果。而異步則是各個(gè)線程獨(dú)立運(yùn)行,誰(shuí)先做完就休息,不用等待。

threadlocal

import threading #導(dǎo)入模塊l = threading.local() #實(shí)例化local,注意這個(gè)local和Lock互斥鎖的名稱不同。def work(name): #創(chuàng)建函數(shù)l.name = name #將參數(shù)name傳遞給local實(shí)例對(duì)象的name屬性。注意:這里的l.name是創(chuàng)建的對(duì)象屬性。works() #調(diào)用work函數(shù)def works(): #創(chuàng)建函數(shù)name = l.nameprint('hello,%s,線程的name是%s'%(name,threading.current_thread().name))t1 = threading.Thread(target=work,args=('小李',)) #實(shí)例化線程對(duì)象,并調(diào)用work,參數(shù)name是小李。 t2 = threading.Thread(target=work,args=('小王',))#實(shí)例化線程對(duì)象,并調(diào)用work,參數(shù)name是小王。 t1.start() t2.start() t1.join() t2.join()
  • ?

注意:threadlocal是比較方便的共享數(shù)據(jù)處理辦法,他的內(nèi)部類似于一個(gè)字典,Thread.name作為Key,對(duì)應(yīng)的屬性作為Value,當(dāng)Thread-1儲(chǔ)存和取值的時(shí)候,對(duì)應(yīng)的是它的值,從而避免多個(gè)線程對(duì)共有數(shù)據(jù)造成錯(cuò)誤和丟失。

網(wǎng)絡(luò)編程

Tcp/Ip協(xié)議

早期的計(jì)算機(jī)網(wǎng)絡(luò),都是由各廠商自己規(guī)定一套協(xié)議,IBM、Apple和Microsoft都有各自的網(wǎng)絡(luò)協(xié)議,互不兼容為了把全世界的所有不同類型的計(jì)算機(jī)都連接起來(lái),就必須規(guī)定一套全球通用的協(xié)議,為了實(shí)現(xiàn)互聯(lián)網(wǎng)這個(gè)目標(biāo),互聯(lián)網(wǎng)協(xié)議簇(Internet ProtocolSuite)就是通用協(xié)議標(biāo)準(zhǔn)。

因?yàn)榛ヂ?lián)網(wǎng)協(xié)議包含了上百種協(xié)議標(biāo)準(zhǔn),但是最重要的兩個(gè)協(xié)議是TCP和IP協(xié)議,所以,大家把互聯(lián)網(wǎng)的協(xié)議簡(jiǎn)稱TCP/IP協(xié)議

端口

知名端口

知名端口是眾所周知的端口號(hào),范圍從0到1023
例如:
80端口分配給HTTP服務(wù)
21端口分配給FTP服務(wù)
一般情況下,如果一個(gè)程序需要使用知名端口的需要有root權(quán)限

動(dòng)態(tài)端口

動(dòng)態(tài)端口的范圍是從1024到65535
之所以稱為動(dòng)態(tài)端口,是因?yàn)樗话悴还潭ǚ峙淠撤N服務(wù),而是動(dòng)態(tài)分配。
動(dòng)態(tài)分配是指當(dāng)一個(gè)系統(tǒng)進(jìn)程或應(yīng)用程序進(jìn)程需要網(wǎng)絡(luò)通信時(shí),它向主機(jī)申請(qǐng)一個(gè)端口,主機(jī)從可用的端口號(hào)中分配一個(gè)供它使用。當(dāng)這個(gè)進(jìn)程關(guān)閉時(shí),同時(shí)也就釋放了所占用的端口號(hào)。

小結(jié)
端口有什么作用?在兩臺(tái)計(jì)算機(jī)通信時(shí),只發(fā) IP 地址是不夠的,因?yàn)橥慌_(tái)計(jì)算機(jī)上跑著多個(gè)網(wǎng)絡(luò)程序。一個(gè) IP 包來(lái)了之后,到底是交給瀏覽器還是 QQ,就需要端口號(hào)來(lái)區(qū)分。每個(gè)網(wǎng)絡(luò)程序都向操作系統(tǒng)申請(qǐng)唯一的端口號(hào),這樣,兩個(gè)進(jìn)程在兩臺(tái)計(jì)算機(jī)之間建立網(wǎng)絡(luò)連接就需要各自的 IP 地址和各自的端口號(hào)。

Socket-套接字

udp-套接字

from socket import * #導(dǎo)入socket from threading import * #導(dǎo)入threadingudp = socket(AF_INET,SOCK_DGRAM) #創(chuàng)建套接字,基于UDP傳輸協(xié)議。相對(duì)于TCP比較快。AF_INET表示使用IPV4進(jìn)行鏈接。如果使用IPV6則把參數(shù)修改為AF_INET6udp.bind(('',8080)) #綁定任意ip,和8080端口,如果不進(jìn)行綁定,那么每創(chuàng)建一個(gè)套解字就會(huì)使用一個(gè)動(dòng)態(tài)端口。sendip = input('輸入接收方的IP:') sendport = int(input('輸入接收方的端口:'))def sendinfo(): #定義發(fā)送函數(shù)while True:senddata = input('請(qǐng)輸入發(fā)送的內(nèi)容:')udp.sendto(senddata.encode('utf-8'),(sendip,sendport)) #調(diào)用套解字的sendto方法,第一個(gè)參數(shù)為編碼后的數(shù)據(jù),第二個(gè)參數(shù)為接收方的IP和端口。def receiveinfo(): #定義接收函數(shù)while True:recvdata = udp.recvfrom(1024) #調(diào)用recvfrom方法進(jìn)行數(shù)據(jù)接收,并且以元祖的方式返回,第一個(gè)參數(shù)是數(shù)據(jù),第二個(gè)參數(shù)為IP和端口。與發(fā)送格式一致。print(recvdata[1],recvdata[0].decode('utf-8')) #將接收到的數(shù)據(jù)進(jìn)行打印,并將數(shù)據(jù)進(jìn)行解碼。def main():ts = Thread(target=sendinfo) #創(chuàng)建一個(gè)線程運(yùn)行發(fā)送函數(shù)。tr = Thread(target=receiveinfo) #創(chuàng)建一個(gè)線程運(yùn)行接收函數(shù)。ts.start()tr.start()ts.join()tr.join()if __name__ == '__main__':main()

注意:socket套接字是用來(lái)再網(wǎng)絡(luò)間通信的模塊。

tcp-套接字

tcp-套接字 服務(wù)器

from socket import * #導(dǎo)入套接字tcp = socket(AF_INET,SOCK_STREAM) #創(chuàng)建tcp套接字tcp.bind(('',8800)) #綁定ip,和端口,客戶端需要連接這個(gè)ip和端口進(jìn)行服務(wù)器連接。tcp.listen(5) #tcp監(jiān)聽(tīng),參數(shù)為可連接的數(shù)量。newsocket,addr = tcp.accept() #接收客戶端的連接,并返回一個(gè)新的socket和客戶端地址。阻塞程序等待客戶端的接入。while 1: # 表示while True,只要條件類型不是空類型、0和None的False類型則就表示while True。socketDate = newsocket.recv(1024) #接收客戶端的數(shù)據(jù)。if len(socketDate)>0: #如果接收數(shù)據(jù)的長(zhǎng)度大于0,則打印出接收到的信息,如果接收的數(shù)據(jù)長(zhǎng)度為0,則表示客戶端使用close方法關(guān)閉了套接字。print(socketDate.decode('utf-8')) #將接收數(shù)據(jù)解碼為utf-8輸出else: #如果客戶端關(guān)閉了套接字,則跳出循環(huán)breaksendDate = input('請(qǐng)輸入要回復(fù)的內(nèi)容:') #輸入需要回復(fù)的數(shù)據(jù)newsocket.send(sendDate.encode('utf-8')) #使用send將數(shù)據(jù)編碼為utf-8回復(fù)newsocket.close() #關(guān)閉與客戶端通信的套接字。 tcp.close() #關(guān)閉服務(wù)器的套接字,關(guān)閉后將不會(huì)再接收客戶端的連接。

注意:在linux系統(tǒng)中l(wèi)isten的參數(shù)可以忽略,因?yàn)橄到y(tǒng)會(huì)自動(dòng)按照內(nèi)核進(jìn)行最大連接數(shù)的操作,即使填寫參數(shù)也沒(méi)有效果,但是windons和mac中則會(huì)有效。以上是單線程案例。

tcp-套接字 客戶端

from socket import * #導(dǎo)入模塊csocket = socket(AF_INET,SOCK_STREAM) #創(chuàng)建套接字serverIp = input('請(qǐng)輸入服務(wù)器的IP:') csocket.connect((serverIp,8800)) #連接服務(wù)器while 1:sendData = input('請(qǐng)輸入需要發(fā)送打內(nèi)容:') #輸入發(fā)送的內(nèi)容csocket.send(sendData.encode('utf-8')) #編碼發(fā)送recvData = csocket.recv(1024)print('recvData:%s'%recvData.decode('utf-8')) #解碼輸出csocket.close() #關(guān)閉套接字

注意:正常的編程工作中,會(huì)優(yōu)先使用tcp套接字。

交換機(jī)、路由器

交換機(jī)

轉(zhuǎn)發(fā)過(guò)濾:當(dāng)?個(gè)數(shù)據(jù)幀的?的地址在MAC地址表中有映射時(shí),它被轉(zhuǎn)發(fā)到連接?的節(jié)點(diǎn)的端??不是所有端?(如該數(shù)據(jù)幀為?播幀則轉(zhuǎn)發(fā)?所有端?)

學(xué)習(xí)功能:以太?交換機(jī)了解每?端?相連設(shè)備的MAC地址,并將地址同相應(yīng)的端?映射起來(lái)存放在交換機(jī)緩存中的MAC地址表中

交換機(jī)能夠完成多個(gè)電腦的鏈接每個(gè)數(shù)據(jù)包的發(fā)送都是以?播的形式進(jìn)?的,容易堵塞?絡(luò)如果PC不知?標(biāo)IP所對(duì)應(yīng)的的MAC,那么可以看出,pc會(huì)先發(fā)送arp?播,得到對(duì)?的MAC然后,在進(jìn)?數(shù)據(jù)的傳送當(dāng)switch第?次收到arp?播數(shù)據(jù),會(huì)把a(bǔ)rp?播數(shù)據(jù)包轉(zhuǎn)發(fā)給所有端?(除來(lái)源端?);如果以后還有pc詢問(wèn)此IP的MAC,那么只是向?標(biāo)的端?進(jìn)?轉(zhuǎn)發(fā)數(shù)據(jù)。

路由器

路由器(Router)?稱?關(guān)設(shè)備(Gateway)是?于連接多個(gè)邏輯上分開(kāi)的?絡(luò)所謂邏輯?絡(luò)是代表?個(gè)單獨(dú)的?絡(luò)或者?個(gè)??。當(dāng)數(shù)據(jù)從?個(gè)??傳輸?shù)搅?個(gè)??時(shí),可通過(guò)路由器的路由功能來(lái)完成具有判斷?絡(luò)地址和選擇IP路徑的功能

不在同??段的pc,需要設(shè)置默認(rèn)?關(guān)才能把數(shù)據(jù)傳送過(guò)去 通常情況下,都會(huì)把路由器默認(rèn)?關(guān)當(dāng)路由器收到?個(gè)其它?段的數(shù)據(jù)包時(shí),會(huì)根據(jù)“路由表”來(lái)決定,把此數(shù)據(jù)包發(fā)送到哪個(gè)端?;路由表的設(shè)定有靜態(tài)和動(dòng)態(tài)?法每經(jīng)過(guò)?次路由器,那么TTL值就會(huì)減1

網(wǎng)段、ARP、DNS、MAC地址

網(wǎng)段

網(wǎng)段(network segment)一般指一個(gè)計(jì)算機(jī)網(wǎng)絡(luò)中使用同一物理層設(shè)備(傳輸介質(zhì),中繼器,集線器等)能夠直接通訊的那一部分。例如,從192.168.0.1到192.168.255.255這之間就是一個(gè)網(wǎng)段。

A類IP段  0.0.0.0 到127.255.255.255 A類的默認(rèn)子網(wǎng)掩碼 255.0.0.0     一個(gè)子網(wǎng)最多可以容納1677萬(wàn)多臺(tái)電腦
B類IP段  128.0.0.0 到191.255.255.255 B類的默認(rèn)子網(wǎng)掩碼 255.255.0.0    一個(gè)子網(wǎng)最多可以容納6萬(wàn)臺(tái)電腦
C類IP段  192.0.0.0 到223.255.255.255 C類的默認(rèn)子網(wǎng)掩碼 255.255.255.0   一個(gè)子網(wǎng)最多可以容納254臺(tái)電腦

局域網(wǎng)保留地址:
A類:10.0.0.0/8 10.0.0.0-10.255.255.255
B類:172.16.0.0/12 172.16.0.0-172.31.255.255
C類:192.168.0.0/16 192.168.0.0~192.168.255.255

注意:C類地址必須前三位一致的才算是一個(gè)局域網(wǎng),可以不使用路由器進(jìn)行通信,例如192.168.1.1-192.168.1.254 是一個(gè)局域網(wǎng),B類地址則必須前兩位一致才算是一個(gè)局域網(wǎng)。以此類推。即子網(wǎng)掩碼有幾位相同的則需要有幾位一致的。

ARP

地址解析協(xié)議,即ARP(Address Resolution Protocol),是根據(jù)IP地址獲取物理地址的一個(gè)TCP/IP協(xié)議。主機(jī)發(fā)送信息時(shí)將包含目標(biāo)IP地址的ARP請(qǐng)求廣播到網(wǎng)絡(luò)上的所有主機(jī),并接收返回消息,以此確定目標(biāo)的物理地址;收到返回消息后將該IP地址和物理地址存入本機(jī)ARP緩存中并保留一定時(shí)間,下次請(qǐng)求時(shí)直接查詢ARP緩存以節(jié)約資源。地址解析協(xié)議是建立在網(wǎng)絡(luò)中各個(gè)主機(jī)互相信任的基礎(chǔ)上的,網(wǎng)絡(luò)上的主機(jī)可以自主發(fā)送ARP應(yīng)答消息,其他主機(jī)收到應(yīng)答報(bào)文時(shí)不會(huì)檢測(cè)該報(bào)文的真實(shí)性就會(huì)將其記入本機(jī)ARP緩存;由此攻擊者就可以向某一主機(jī)發(fā)送偽ARP應(yīng)答報(bào)文,使其發(fā)送的信息無(wú)法到達(dá)預(yù)期的主機(jī)或到達(dá)錯(cuò)誤的主機(jī),這就構(gòu)成了一個(gè)ARP欺騙。ARP命令可用于查詢本機(jī)ARP緩存中IP地址和MAC地址的對(duì)應(yīng)關(guān)系、添加或刪除靜態(tài)對(duì)應(yīng)關(guān)系等。相關(guān)協(xié)議有RARP、代理ARP。NDP用于在IPv6中代替地址解析協(xié)議。

工作過(guò)程
主機(jī)A的IP地址為192.168.1.1,MAC地址為0A-11-22-33-44-01;
主機(jī)B的IP地址為192.168.1.2,MAC地址為0A-11-22-33-44-02;
當(dāng)主機(jī)A要與主機(jī)B通信時(shí),地址解析協(xié)議可以將主機(jī)B的IP地址(192.168.1.2)解析成主機(jī)B的MAC地址,以下為工作流程:
第1步:根據(jù)主機(jī)A上的路由表內(nèi)容,IP確定用于訪問(wèn)主機(jī)B的轉(zhuǎn)發(fā)IP地址是192.168.1.2。然后A主機(jī)在自己的本地ARP緩存中檢查主機(jī)B的匹配MAC地址。
第2步:如果主機(jī)A在ARP緩存中沒(méi)有找到映射,它將詢問(wèn)192.168.1.2的硬件地址,從而將ARP請(qǐng)求幀廣播到本地網(wǎng)絡(luò)上的所有主機(jī)。源主機(jī)A的IP地址和MAC地址都包括在ARP請(qǐng)求中。本地網(wǎng)絡(luò)上的每臺(tái)主機(jī)都接收到ARP請(qǐng)求并且檢查是否與自己的IP地址匹配。如果主機(jī)發(fā)現(xiàn)請(qǐng)求的IP地址與自己的IP地址不匹配,它將丟棄ARP請(qǐng)求。
第3步:主機(jī)B確定ARP請(qǐng)求中的IP地址與自己的IP地址匹配,則將主機(jī)A的IP地址和MAC地址映射添加到本地ARP緩存中。
第4步:主機(jī)B將包含其MAC地址的ARP回復(fù)消息直接發(fā)送回主機(jī)A。
第5步:當(dāng)主機(jī)A收到從主機(jī)B發(fā)來(lái)的ARP回復(fù)消息時(shí),會(huì)用主機(jī)B的IP和MAC地址映射更新ARP緩存。本機(jī)緩存是有生存期的,生存期結(jié)束后,將再次重復(fù)上面的過(guò)程。主機(jī)B的MAC地址一旦確定,主機(jī)A就能向主機(jī)B發(fā)送IP通信了。

DNS

DNS服務(wù)器是(Domain Name System或者Domain Name Service)域名系統(tǒng)或者域名服務(wù),域名系統(tǒng)為Internet上的主機(jī)分配域名地址和IP地址。用戶使用域名地址,該系統(tǒng)就會(huì)自動(dòng)把域名地址轉(zhuǎn)為IP地址。域名服務(wù)是運(yùn)行域名系統(tǒng)的Internet工具。執(zhí)行域名服務(wù)的服務(wù)器稱之為DNS服務(wù)器,通過(guò)DNS服務(wù)器來(lái)應(yīng)答域名服務(wù)的查詢。

MAC地址

MAC(Media Access Control或者M(jìn)edium Access Control)地址,意譯為媒體訪問(wèn)控制,或稱為物理地址、硬件地址,用來(lái)定義網(wǎng)絡(luò)設(shè)備的位置。在OSI模型中,第三層網(wǎng)絡(luò)層負(fù)責(zé) IP地址,第二層數(shù)據(jù)鏈路層則負(fù)責(zé) MAC地址。因此一個(gè)主機(jī)會(huì)有一個(gè)MAC地址,而每個(gè)網(wǎng)絡(luò)位置會(huì)有一個(gè)專屬于它的IP地址。

MAC(Medium/Media Access Control)地址,用來(lái)表示互聯(lián)網(wǎng)上每一個(gè)站點(diǎn)的標(biāo)識(shí)符,采用十六進(jìn)制數(shù)表示,共六個(gè)字節(jié)(48位)。其中,前三個(gè)字節(jié)是由IEEE的注冊(cè)管理機(jī)構(gòu)RA負(fù)責(zé)給不同廠家分配的代碼(高位24位),也稱為"編制上唯一的標(biāo)識(shí)符"(Organizationally Unique Identifier),后三個(gè)字節(jié)(低位24位)由各廠家自行指派給生產(chǎn)的適配器接口,稱為擴(kuò)展標(biāo)識(shí)符(唯一性)。一個(gè)地址塊可以生成2個(gè)不同的地址。MAC地址實(shí)際上就是適配器地址或適配器標(biāo)識(shí)符EUI-48[1]

注意:在真正的信息傳輸中,發(fā)送者的ip和接收方的ip和數(shù)據(jù)包內(nèi)容是不變的,期間會(huì)通過(guò)各個(gè)路由器的mac地址進(jìn)行傳輸。簡(jiǎn)單可以理解為,在網(wǎng)上買了一件衣服,包裹的發(fā)送方是商家(可以理解為發(fā)送者的IP),包裹的接收方是自己(理解為接收者的IP),期間的各個(gè)快遞中轉(zhuǎn)站就可以理解為各個(gè)路由器的mac地址,最后由數(shù)據(jù)將會(huì)傳遞到自己手中。

TCP3次握手、4次揮手和10種狀態(tài)

TCP3次握手

在TCP/IP協(xié)議中,TCP協(xié)議提供可靠的連接服務(wù),采用三次握手建立一個(gè)連接.
第一次握手:建立連接時(shí),客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn); SYN:同步序列編號(hào)(Synchronize Sequence Numbers)
第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手.
完成三次握手,客戶端與服務(wù)器開(kāi)始傳送數(shù)據(jù)

關(guān)閉連接(四次揮手)

第一次揮手:客戶端發(fā)送FIN+ACK包(序號(hào)為seq=a,確認(rèn)序號(hào)ack=b)給服務(wù)端,用來(lái)關(guān)閉客戶端到服務(wù)端的數(shù)據(jù)傳送,客戶端進(jìn)入FIN_WAIT_1狀態(tài)。
第二次揮手:服務(wù)端收到FIN+ACK包后,發(fā)送ACK包給客戶端進(jìn)行確認(rèn),服務(wù)端進(jìn)入CLOSE_WAIT狀態(tài)。客戶端收到ACK包后進(jìn)入FIN_WAIT_2狀態(tài)。到這里,關(guān)閉一個(gè)單向通道。
第三次揮手:服務(wù)端發(fā)送FIN+ACK包給客戶端,服務(wù)端進(jìn)入LAST_ACK狀態(tài)。
第四次揮手:客戶端收到FIN+ACK包后,發(fā)送ACK包給服務(wù)端進(jìn)行確認(rèn),客戶端進(jìn)入TIME_WAIT狀態(tài),在等待30秒(可修改)后進(jìn)入CLOSED狀態(tài)。服務(wù)端收到ACK包后進(jìn)入CLOSED狀態(tài),關(guān)閉另一個(gè)單向通道。

TCP十種狀態(tài)

CLOSED:表示關(guān)閉狀態(tài)(初始狀態(tài))。
LISTEN:該狀態(tài)表示服務(wù)器端的某個(gè)SOCKET處于監(jiān)聽(tīng)狀態(tài),可以接受連接。
SYN_SENT:這個(gè)狀態(tài)與SYN_RCVD遙相呼應(yīng),當(dāng)客戶端SOCKET執(zhí)行CONNECT連接時(shí),它首先發(fā)送SYN報(bào)文,隨即進(jìn)入到了SYN_SENT狀態(tài),并等待服務(wù)端的發(fā)送三次握手中的第2個(gè)報(bào)文。SYN_SENT狀態(tài)表示客戶端已發(fā)送SYN報(bào)文。
SYN_RCVD: 該狀態(tài)表示接收到SYN報(bào)文,在正常情況下,這個(gè)狀態(tài)是服務(wù)器端的SOCKET在建立TCP連接時(shí)的三次握手會(huì)話過(guò)程中的一個(gè)中間狀態(tài),很短暫。此種狀態(tài)時(shí),當(dāng)收到客戶端的ACK報(bào)文后,會(huì)進(jìn)入到ESTABLISHED狀態(tài)。
ESTABLISHED:表示連接已經(jīng)建立。
FIN_WAIT_1: FIN_WAIT_1和FIN_WAIT_2狀態(tài)的真正含義都是表示等待對(duì)方的FIN報(bào)文。區(qū)別是: FIN_WAIT_1狀態(tài)是當(dāng)socket在ESTABLISHED狀態(tài)時(shí),想主動(dòng)關(guān)閉連接,向?qū)Ψ桨l(fā)送了FIN報(bào)文,此時(shí)該socket進(jìn)入到FIN_WAIT_1狀態(tài)。 FIN_WAIT_2狀態(tài)是當(dāng)對(duì)方回應(yīng)ACK后,該socket進(jìn)入到FIN_WAIT_2狀態(tài),正常情況下,對(duì)方應(yīng)馬上回應(yīng)ACK報(bào)文,所以FIN_WAIT_1狀態(tài)一般較難見(jiàn)到,而FIN_WAIT_2狀態(tài)可用netstat看到。
FIN_WAIT_2:主動(dòng)關(guān)閉鏈接的一方,發(fā)出FIN收到ACK以后進(jìn)入該狀態(tài)。稱之為半連接或半關(guān)閉狀態(tài)。該狀態(tài)下的socket只能接收數(shù)據(jù),不能發(fā)。
TIME_WAIT: 表示收到了對(duì)方的FIN報(bào)文,并發(fā)送出了ACK報(bào)文,等2MSL后即可回到CLOSED可用狀態(tài)。如果FIN_WAIT_1狀態(tài)下,收到對(duì)方同時(shí)帶 FIN標(biāo)志和ACK標(biāo)志的報(bào)文時(shí),可以直接進(jìn)入到TIME_WAIT狀態(tài),而無(wú)須經(jīng)過(guò)FIN_WAIT_2狀態(tài)。
CLOSE_WAIT: 此種狀態(tài)表示在等待關(guān)閉。當(dāng)對(duì)方關(guān)閉一個(gè)SOCKET后發(fā)送FIN報(bào)文給自己,系統(tǒng)會(huì)回應(yīng)一個(gè)ACK報(bào)文給對(duì)方,此時(shí)則進(jìn)入到CLOSE_WAIT狀態(tài)。接下來(lái)呢,察看是否還有數(shù)據(jù)發(fā)送給對(duì)方,如果沒(méi)有可以 close這個(gè)SOCKET,發(fā)送FIN報(bào)文給對(duì)方,即關(guān)閉連接。所以在CLOSE_WAIT狀態(tài)下,需要關(guān)閉連接。
LAST_ACK: 該狀態(tài)是被動(dòng)關(guān)閉一方在發(fā)送FIN報(bào)文后,最后等待對(duì)方的ACK報(bào)文。當(dāng)收到ACK報(bào)文后,即可以進(jìn)入到CLOSED可用狀態(tài)。

tcp第十一種狀態(tài):
CLOSING:這種狀態(tài)較特殊,屬于一種較罕見(jiàn)的狀態(tài)。正常情況下,當(dāng)你發(fā)送FIN報(bào)文后,按理來(lái)說(shuō)是應(yīng)該先收到(或同時(shí)收到)對(duì)方的ACK報(bào)文,再收到對(duì)方的FIN報(bào)文。但是CLOSING狀態(tài)表示你發(fā)送FIN報(bào)文后,并沒(méi)有收到對(duì)方的ACK報(bào)文,反而卻也收到了對(duì)方的FIN報(bào)文。什么情況下會(huì)出現(xiàn)此種情況呢?如果雙方幾乎在同時(shí)close一個(gè)SOCKET的話,那么就出現(xiàn)了雙方同時(shí)發(fā)送FIN報(bào)文的情況,也即會(huì)出現(xiàn)CLOSING狀態(tài),表示雙方都正在關(guān)閉SOCKET連接。

TCP的2MSL

2MSL即兩倍的MSL,TCP的TIME_WAIT狀態(tài)也稱為2MSL等待狀態(tài),
當(dāng)TCP的?端發(fā)起主動(dòng)關(guān)閉,在發(fā)出最后?個(gè)ACK包后,即第3次握 ?完成后發(fā)送了第四次握?的ACK包后就進(jìn)?了TIME_WAIT狀態(tài),必須在此狀態(tài)上停留兩倍的MSL時(shí)間,等待2MSL時(shí)間主要?的是怕最后?個(gè) ACK包對(duì)?沒(méi)收到,那么對(duì)?在超時(shí)后將重發(fā)第三次握?的FIN包,主動(dòng)關(guān)閉端接到重發(fā)的FIN包后可以再發(fā)?個(gè)ACK應(yīng)答包。

在TIME_WAIT狀態(tài) 時(shí)兩端的端?不能使?,要等到2MSL時(shí)間結(jié)束才可繼續(xù)使?。當(dāng)連接處于2MSL等待階段時(shí)任何遲到的報(bào)?段都將被丟棄。不過(guò)在實(shí)際應(yīng)?中可以通過(guò)設(shè)置 SO_REUSEADDR選項(xiàng)達(dá)到不必等待2MSL時(shí)間結(jié)束再使?此端?。

TCP?連接和短連接

短鏈接

?連接

常見(jiàn)的網(wǎng)絡(luò)攻擊

DDOS攻擊

注意:簡(jiǎn)單的理解DDOS攻擊就是使用TCP的三次握手協(xié)議,編寫代碼使用多線程或者多進(jìn)程方式惡意的不發(fā)送第三次握手導(dǎo)致服務(wù)器listen隊(duì)列爆滿,使正常的客戶無(wú)法正常連接。

DNS攻擊

DNS欺騙就是攻擊者冒充域名服務(wù)器的一種欺騙行為。 原理:如果可以冒充域名服務(wù)器,然后把查詢的IP地址設(shè)為攻擊者的IP地址,這樣的話,用戶上網(wǎng)就只能看到攻擊者的主頁(yè),而不是用戶想要取得的網(wǎng)站的主頁(yè)了,這就是DNS欺騙的基本原理。DNS欺騙其實(shí)并不是真的"黑掉"了對(duì)方的網(wǎng)站,而是冒名頂替、招搖撞騙罷了。

ARP攻擊

ARP攻擊就是通過(guò)偽造IP地址和MAC地址實(shí)現(xiàn)ARP欺騙,能夠在網(wǎng)絡(luò)中產(chǎn)生大量的ARP通信量使網(wǎng)絡(luò)阻塞,攻擊者只要持續(xù)不斷的發(fā)出偽造的ARP響應(yīng)包就能更改目標(biāo)主機(jī)ARP緩存中的IP-MAC條目,造成網(wǎng)絡(luò)中斷或中間人攻擊。
ARP攻擊主要是存在于局域網(wǎng)網(wǎng)絡(luò)中,局域網(wǎng)中若有一臺(tái)計(jì)算機(jī)感染ARP木馬,則感染該ARP木馬的系統(tǒng)將會(huì)試圖通過(guò)“ARP欺騙”手段截獲所在網(wǎng)絡(luò)內(nèi)其它計(jì)算機(jī)的通信信息,并因此造成網(wǎng)內(nèi)其它計(jì)算機(jī)的通信故障。
攻擊者向電腦A發(fā)送一個(gè)偽造的ARP響應(yīng),告訴電腦A:電腦B的IP地址192.168.0.2對(duì)應(yīng)的MAC地址是00-aa-00-62-c6-03,電腦A信以為真,將這個(gè)對(duì)應(yīng)關(guān)系寫入自己的ARP緩存表中,以后發(fā)送數(shù)據(jù)時(shí),將本應(yīng)該發(fā)往電腦B的數(shù)據(jù)發(fā)送給了攻擊者。同樣的,攻擊者向電腦B也發(fā)送一個(gè)偽造的ARP響應(yīng),告訴電腦B:電腦A的IP地址192.168.0.1對(duì)應(yīng)的MAC地址是00-aa-00-62-c6-03,電腦B也會(huì)將數(shù)據(jù)發(fā)送給攻擊者。
至此攻擊者就控制了電腦A和電腦B之間的流量,他可以選擇被動(dòng)地監(jiān)測(cè)流量,獲取密碼和其他涉密信息,也可以偽造數(shù)據(jù),改變電腦A和電腦B之間的通信內(nèi)容。

客戶端:

?

1.Python面向?qū)ο?/strong>

創(chuàng)建類

使用class語(yǔ)句來(lái)創(chuàng)建一個(gè)新類,class之后為類的名稱并以冒號(hào)結(jié)尾,如下實(shí)例:

class ClassName:'類的幫助信息' #類文檔字符串class_suite #類體

實(shí)例: class Employee:'所有員工的基類'empCount = 0def __init__(self, name, salary):self.name = nameself.salary = salaryEmployee.empCount += 1def displayCount(self):print "Total Employee %d" % Employee.empCountdef displayEmployee(self):print "Name : ", self.name, ", Salary: ", self.salary"創(chuàng)建 Employee 類的第一個(gè)對(duì)象" emp1 = Employee("Zara", 2000) "創(chuàng)建 Employee 類的第二個(gè)對(duì)象" emp2 = Employee("Manni", 5000) emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount

輸出結(jié)果如下:

Name : Zara ,Salary: 2000 Name : Manni ,Salary: 5000 Total Employee 2 類的私有屬性:

__private_attrs:兩個(gè)下劃線開(kāi)頭,聲明該屬性為私有,不能在類的外部被使用或直接訪問(wèn)。在類內(nèi)部的方法中使用時(shí)?self.__private_attrs

類的私有方法: __private_method:兩個(gè)下劃線開(kāi)頭,聲明該方法為私有方法,不能在類地外部調(diào)用。在類的內(nèi)部調(diào)用?self.__private_methods

class JustCounter:__secretCount = 0 # 私有變量publicCount = 0 # 公開(kāi)變量def count(self):self.__secretCount += 1self.publicCount += 1print self.__secretCountcounter = JustCounter() counter.count() counter.count() print counter.publicCount print counter.__secretCount # 報(bào)錯(cuò),實(shí)例不能訪問(wèn)私有變量

輸出結(jié)果如下:1 2 2 Traceback (most recent call last):File "test.py", line 17, in <module>print counter.__secretCount # 報(bào)錯(cuò),實(shí)例不能訪問(wèn)私有變量 AttributeError: JustCounter instance has no attribute '__secretCount'單下劃線,雙下劃線,頭尾雙下劃線說(shuō)明:
  • __foo__: 定義的是特列方法,類似?__init__()?之類的。

  • _foo: 以單下劃線開(kāi)頭的表示的是 protected 類型的變量,即保護(hù)類型只能允許其本身與子類進(jìn)行訪問(wèn),不能用于?from module import *

  • __foo: 雙下劃線的表示的是私有類型(private)的變量, 只能是允許這個(gè)類本身進(jìn)行訪問(wèn)了。

2.正則表達(dá)式

re.match只匹配字符串的開(kāi)始,如果字符串開(kāi)始不符合正則表達(dá)式,則匹配失敗,函數(shù)返回None;而re.search匹配整個(gè)字符串,直到找到一個(gè)匹配。

import reline = "Cats are smarter than dogs";matchObj = re.match( r'dogs', line, re.M|re.I) if matchObj:print "match --> matchObj.group() : ", matchObj.group() else:print "No match!!"matchObj = re.search( r'dogs', line, re.M|re.I) if matchObj:print "search --> matchObj.group() : ", matchObj.group() else:print "No match!!"

運(yùn)行結(jié)果如下:

No match!! search --> matchObj.group() : dogs匹配和檢索:

Python 的 re 模塊提供了re.sub用于替換字符串中的匹配項(xiàng)。

語(yǔ)法:

re.sub(pattern, repl, string, count=0, flags=0)

參數(shù):

  • pattern : 正則中的模式字符串。
  • repl : 替換的字符串,也可為一個(gè)函數(shù)。
  • string : 要被查找替換的原始字符串。
  • count : 模式匹配后替換的最大次數(shù),默認(rèn) 0 表示替換所有的匹配。

實(shí)例

import rephone = "2004-959-559 # 這是一個(gè)國(guó)外電話號(hào)碼"# 刪除字符串中的 Python注釋 num = re.sub(r'#.*$', "", phone) print "電話號(hào)碼是: ", num# 刪除非數(shù)字(-)的字符串 num = re.sub(r'\D', "", phone) print "電話號(hào)碼是 : ", num

以上實(shí)例執(zhí)行結(jié)果如下: 電話號(hào)碼是: 2004-959-559 電話號(hào)碼是 : 2004959559下表列出了正則表達(dá)式模式語(yǔ)法中的特殊元素。如果你使用模式的同時(shí)提供了可選的標(biāo)志參數(shù),某些模式元素的含義會(huì)改變 模 ? ? ?式描述
^匹配字符串的開(kāi)頭
$匹配字符串的末尾。
.匹配任意字符,除了換行符,當(dāng)re.DOTALL標(biāo)記被指定時(shí),則可以匹配包括換行符的任意字符。
[...]用來(lái)表示一組字符,單獨(dú)列出:[amk] 匹配 'a','m'或'k'
[^...]不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re*匹配0個(gè)或多個(gè)的表達(dá)式。
re+匹配1個(gè)或多個(gè)的表達(dá)式。
re?匹配0個(gè)或1個(gè)由前面的正則表達(dá)式定義的片段,非貪婪方式
re{ n}?
re{ n,}精確匹配n個(gè)前面表達(dá)式。
re{ n, m}匹配 n 到 m 次由前面的正則表達(dá)式定義的片段,貪婪方式
a| b匹配a或b
(re)G匹配括號(hào)內(nèi)的表達(dá)式,也表示一個(gè)組
(?imx)正則表達(dá)式包含三種可選標(biāo)志:i, m, 或 x 。只影響括號(hào)中的區(qū)域。
(?-imx)正則表達(dá)式關(guān)閉 i, m, 或 x 可選標(biāo)志。只影響括號(hào)中的區(qū)域。
(?: re)類似 (...), 但是不表示一個(gè)組
(?imx: re)在括號(hào)中使用i, m, 或 x 可選標(biāo)志
(?-imx: re)在括號(hào)中不使用i, m, 或 x 可選標(biāo)志
(?#...)注釋.
(?= re)

前向肯定界定符。如果所含正則表達(dá)式,以 ... 表示,在當(dāng)前位置成功匹配時(shí)成功,否則失敗。

但一旦所含表達(dá)式已經(jīng)嘗試,匹配引擎根本沒(méi)有提高;模式的剩余部分還要嘗試界定符的右邊。

(?! re)前向否定界定符。與肯定界定符相反;當(dāng)所含表達(dá)式不能在字符串當(dāng)前位置匹配時(shí)成功
(?> re)匹配的獨(dú)立模式,省去回溯。
\w匹配字母數(shù)字及下劃線
\W匹配非字母數(shù)字及下劃線
\s匹配任意空白字符,等價(jià)于 [\t\n\r\f].
\S匹配任意非空字符
\d匹配任意數(shù)字,等價(jià)于 [0-9].
\D匹配任意非數(shù)字
\A匹配字符串開(kāi)始
\Z匹配字符串結(jié)束,如果是存在換行,只匹配到換行前的結(jié)束字符串。c
\z匹配字符串結(jié)束
\G匹配最后匹配完成的位置。
\b匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等.匹配一個(gè)換行符。匹配一個(gè)制表符。等
\1...\9匹配第n個(gè)分組的內(nèi)容。
\10匹配第n個(gè)分組的內(nèi)容,如果它經(jīng)匹配。否則指的是八進(jìn)制字符碼的表達(dá)式。

python高級(jí)之面向?qū)ο蟾呒?jí)

本節(jié)內(nèi)容

  • 成員修飾符
  • 特殊成員
  • 類與對(duì)象
  • 異常處理
  • 反射/自省
  • 單例模式
  • 1.成員修飾符

    python的類中只有私有成員和公有成員兩種,不像c++中的類有公有成員(public),私有成員(private)和保護(hù)成員(protected).并且python中沒(méi)有關(guān)鍵字去修飾成員,默認(rèn)python中所有的成員都是公有成員,但是私有成員是以兩個(gè)下劃線開(kāi)頭的名字標(biāo)示私有成員,私有成員不允許直接訪問(wèn),只能通過(guò)內(nèi)部方法去訪問(wèn),私有成員也不允許被繼承。

    class a: # 說(shuō)明父類的私有成員無(wú)法在子類中繼承def __init__(self):self.ge=123self.__gene=456class b(a):def __init__(self,name):self.name=nameself.__age=18super(b,self).__init__() # 這一行會(huì)報(bào)錯(cuò)def show(self):print(self.name)print(self.__age)print(self.ge)print(self.__gene) # 這一行也會(huì)報(bào)錯(cuò) obj=b("xiaoming") print(obj.name) print(obj.ge) # print(obj.__gene) # 這個(gè)也會(huì)報(bào)錯(cuò) obj.show()

    上面就是類里面的私有成員了。

    2.特殊成員

    1.__init__

    __init__方法可以簡(jiǎn)單的理解為類的構(gòu)造方法(實(shí)際并不是構(gòu)造方法,只是在類生成對(duì)象之后就會(huì)被執(zhí)行),之前已經(jīng)在上一篇博客中說(shuō)明過(guò)了。

    2.__del__

    __del__方法是類中的析構(gòu)方法,當(dāng)對(duì)象消亡的時(shí)候(被解釋器的垃圾回收的時(shí)候會(huì)執(zhí)行這個(gè)方法)這個(gè)方法默認(rèn)是不需要寫的,不寫的時(shí)候,默認(rèn)是不做任何操作的。因?yàn)槟悴恢缹?duì)象是在什么時(shí)候被垃圾回收掉,所以,除非你確實(shí)要在這里面做某些操作,不然不要自定義這個(gè)方法。

    3.__call__

    __call__方法在類的對(duì)象被執(zhí)行的時(shí)候(obj()或者 類()())會(huì)執(zhí)行。

    4.__int__

    __int__方法,在對(duì)象被int()包裹的時(shí)候會(huì)被執(zhí)行,例如int(obj)如果obj對(duì)象沒(méi)有、__int__方法,那么就會(huì)報(bào)錯(cuò)。在這個(gè)方法中返回的值被傳遞到int類型中進(jìn)行轉(zhuǎn)換。

    5.__str__

    __str__方法和int方法一樣,當(dāng)對(duì)象被str(obj)包裹的時(shí)候,如果對(duì)象中沒(méi)有這個(gè)方法將會(huì)報(bào)錯(cuò),如果有這個(gè)方法,str()將接收這個(gè)方法返回的值在轉(zhuǎn)換成字符串。

    6.__add__

    __add__方法在兩個(gè)對(duì)象相加的時(shí)候,調(diào)用第一個(gè)對(duì)象的__add__方法,將第二個(gè)對(duì)象傳遞進(jìn)來(lái),至于怎么處理以及返回值,那是程序員自定義的,就如下面的例子:

    class abc:def __init__(self,age):self.age=agedef __add__(self,obj):return self.age+obj.age a1=abc(18) a2=abc(20) print(a1+a2) #執(zhí)行結(jié)果:38

    7.__dict__

    __dict__方法在類里面有,在對(duì)象里面也有,這個(gè)方法是以字典的形式列出類或?qū)ο笾械乃谐蓡T。就像下面的例子:

    class abc:def __init__(self,age):self.age=agedef __add__(self,obj):return self.age+obj.age a1=abc(18) print(abc.__dict__) print(a1.__dict__) #執(zhí)行結(jié)果: {'__add__': <function abc.__add__ at 0x0000020666C9E2F0>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'abc' objects>, '__init__': <function abc.__init__ at 0x0000020666C9E268>, '__doc__': None, '__dict__': <attribute '__dict__' of 'abc' objects>} {'age': 18}

    8.__getitem__ __setitem__ __delitem__

    __getitem__方法匹配 對(duì)象[索引] 這種方式,__setitem__匹配 對(duì)象[索引]=value 這種方式,__delitem__匹配 del 對(duì)象[索引] 這種方式,例子如下:

    class Foo:def __init__(self,name,age):self.name=nameself.age=agedef __getitem__(self, item): # 匹配:對(duì)象[item]這種形式return item+10def __setitem__(self, key, value): # 匹配:對(duì)象[key]=value這種形式print(key,value)def __delitem__(self, key): # 匹配:del 對(duì)象[key]這種形式print(key)li=Foo("alex",18) print(li[10]) li[10]=100 del li[10] 執(zhí)行結(jié)果: 20 10 100 10

    9.__getslice__ __setslice__ __delslice__

    這三種方式在python2.7中還存在,用來(lái)對(duì)對(duì)象進(jìn)行切片的,但是在python3之后,將這些特殊方法給去掉了,統(tǒng)一使用上面的方式對(duì)對(duì)象進(jìn)行切片,因此在使用__getitem__ __setitem__ 這兩個(gè)方法之前要先判斷傳遞進(jìn)參數(shù)的類型是不是slice對(duì)象。例子如下:

    class Foo:def __init__(self,name,age):self.name=nameself.age=ageself.li=[1,2,3,4,5,6,7]def __getitem__(self, item): # 匹配:對(duì)象[item]這種形式if isinstance(item,slice): # 如果是slice對(duì)象,返回切片后的結(jié)果return self.li[item] # 返回切片結(jié)果elif isinstance(item,int): # 如果是整形,說(shuō)明是索引return item+10def __setitem__(self, key, value): # 匹配:對(duì)象[key]=value這種形式print(key,value)def __delitem__(self, key): # 匹配:del 對(duì)象[key]這種形式print(key)def __getslice__(self,index1,index2):print(index1,index2)li=Foo("alex",18) print(li[3:5]) #執(zhí)行結(jié)果: [4, 5]

    10. __iter__

    類的對(duì)象如果想要變成一個(gè)可迭代對(duì)象,那么對(duì)象中必須要有__iter__方法,并且這個(gè)方法返回的是一個(gè)迭代器。

    for 循環(huán)的對(duì)象如果是一個(gè)可迭代的對(duì)象,那么會(huì)先執(zhí)行對(duì)象中的__iter__方法,獲取到迭代器,然后再執(zhí)行迭代器中的__next__方法獲取數(shù)據(jù)。如果for循環(huán)的是一個(gè)迭代器,那么直接執(zhí)行迭代器中的__next__方法。

    class Foo:def __init__(self,name,age):self.name=nameself.age=agedef __iter__(self):return iter([1,2,3,4,5]) # 返回的是一個(gè)迭代器 li=Foo("alex",18)# 1.如果類中有__iter__方法,他的對(duì)象就是可迭代對(duì)象 # 2.對(duì)象.__iter()的返回值是一個(gè)迭代器 # 3.for循環(huán)的如果是迭代器,直接執(zhí)行.next方法 # 4.for循環(huán)的如果是可迭代對(duì)象,先執(zhí)行對(duì)象.__iter(),獲取迭代器再執(zhí)行nextfor i in li:print(i) #執(zhí)行結(jié)果: 1 2 3 4 5

    11.isinstance和issubclass

    之前講過(guò)isinstance可以判斷一個(gè)變量是否是某一種數(shù)據(jù)類型,其實(shí),isinstance不只可以判斷數(shù)據(jù)類型,也可以判斷對(duì)象是否是這個(gè)類的對(duì)象或者是這個(gè)類的子類的對(duì)象,代碼如下:

    class Foo:def __init__(self,name,age):self.name=nameself.age=age class Son(Foo):pass obj=Son("xiaoming",18) print(isinstance(obj,Foo)) 執(zhí)行結(jié)果:True

    issubclass用來(lái)判斷一個(gè)類是否是某個(gè)類的子類,返回的是一個(gè)bool類型數(shù)據(jù),代碼如下:

    class Foo:def __init__(self,name,age):self.name=nameself.age=age class Son(Foo):pass obj=Son("xiaoming",18) print(issubclass(Son,Foo)) 執(zhí)行結(jié)果:True

    3.類與對(duì)象

    __new__和__metaclass__

    在python中,一切皆對(duì)象,我們定義的類其實(shí)。。。也是一個(gè)對(duì)象,那么,類本身是誰(shuí)的對(duì)象呢?在python2.2之前(或者叫經(jīng)典類中),所有的類,都是class的對(duì)象,但是在新式類中,為了將類型(int,str,float等)和類統(tǒng)一,所以,所有的類都是type類型的對(duì)象。當(dāng)然,這個(gè)規(guī)則可以被修改,在類中有一個(gè)屬性 __metaclass__ 可以指定當(dāng)前類該由哪個(gè)類進(jìn)行實(shí)例化。而創(chuàng)建對(duì)象過(guò)程中,其實(shí)構(gòu)造器不是__init__方法,而是__new__方法,這個(gè)方法會(huì)返回一個(gè)對(duì)象,這才是對(duì)象的構(gòu)造器。下面是一個(gè)解釋類實(shí)例化對(duì)象內(nèi)部實(shí)現(xiàn)過(guò)程的代碼段:

    class Mytype(type):def __init__(self, what, bases=None, dict=None):super(Mytype,self).__init__(what, bases, dict)def __call__(self, *args, **kwargs):obj=self.__new__(self)self.__init__(obj, *args, **kwargs)return obj class Foo:__metaclass__=Mytypedef __init__(self,name,age):self.name=nameself.age=agedef __new__(cls, *args, **kwargs):return object.__new__(cls) obj=Foo("xiaoming",18) print(obj.name,obj.age) 執(zhí)行結(jié)果:xiaoming 18

    4.異常處理

    python中使用try except finally組合來(lái)實(shí)現(xiàn)異常撲捉,不像java中是使用try catch finally......其中,except中的Exception是所有異常的父類,下面是一個(gè)異常處理的示例:

    try:int("aaa") #可能出現(xiàn)異常的代碼 except IndexError as e: # 捕捉索引異常的子異常,注意,這里的as e在老版本的py中可以寫成,e但是新版本中用as e,",e"未來(lái)可能會(huì)淘汰print("IndexError:",e) except ValueError as e: # 捕捉value錯(cuò)誤的子異常print("ValueError:",e) except Exception as e: # 如果上面兩個(gè)異常沒(méi)有捕獲到,那么使用Exception捕獲,Exception能夠捕獲所有的異常print("Exception:",e) else: # 如果沒(méi)有異常發(fā)生,執(zhí)行else中的代碼塊print("true") finally: # 不管是否發(fā)生異常,在最后都會(huì)執(zhí)行finally中的代碼,假如try里面的代碼正常執(zhí)行,先執(zhí)行else中的代碼,再執(zhí)行finally中的代碼print("finally") 執(zhí)行結(jié)果: ValueError: invalid literal for int() with base 10: 'aaa' finally

    那么既然Exception是所有異常的父類,我們可以自已定義Exception的子類,實(shí)現(xiàn)自定義異常處理,下面就是實(shí)現(xiàn)例子:

    class OldBoyError(Exception): # 自定義錯(cuò)誤類型def __init__(self,message):self.message=messagedef __str__(self): # 打印異常的時(shí)候會(huì)調(diào)用對(duì)象里面的__str__方法返回一個(gè)字符串return self.message try:raise OldBoyError("我錯(cuò)了...") # raise是主動(dòng)拋出異常,可以調(diào)用自定義的異常拋出異常 except OldBoyError as e:print(e) 執(zhí)行結(jié)果:我錯(cuò)了...

    異常處理里面還有一個(gè)斷言,一般用在判斷執(zhí)行環(huán)境上面,只要斷言后面的條件不滿足,那么就拋出異常,并且后面的代碼不執(zhí)行了。

    print(123) assert 1==2 # 斷言,故意拋出異常,做環(huán)境監(jiān)測(cè)用,環(huán)境監(jiān)測(cè)不通過(guò),報(bào)錯(cuò)并結(jié)束程序 print("456") 執(zhí)行結(jié)果:assert 1==2 # 斷言,故意拋出異常,做環(huán)境監(jiān)測(cè)用,環(huán)境監(jiān)測(cè)不通過(guò),報(bào)錯(cuò)并結(jié)束程序 123 AssertionError

    5.反射/自省

    python中的反射/自省的實(shí)現(xiàn),是通過(guò)hasattr、getattr、setattr、delattr四個(gè)內(nèi)置函數(shù)實(shí)現(xiàn)的,其實(shí)這四個(gè)內(nèi)置函數(shù)不只可以用在類和對(duì)象中,也可以用在模塊等其他地方,只是在類和對(duì)象中用的很多,所以單獨(dú)提出來(lái)進(jìn)行解釋。

  • hasattr(key)返回的是一個(gè)bool值,判斷某個(gè)成員或者屬性在不在類或者對(duì)象中
  • getattr(key,default=xxx)獲取類或者對(duì)象的成員或?qū)傩?#xff0c;如果不存在,則會(huì)拋出AttributeError異常,如果定義了default那么當(dāng)沒(méi)有屬性的時(shí)候會(huì)返回默認(rèn)值。
  • setattr(key,value)假如有這個(gè)屬性,那么更新這個(gè)屬性,如果沒(méi)有就添加這個(gè)屬性并賦值value
  • delattr(key)刪除某個(gè)屬性
  • 注意,上面的key都是字符串,而不是變量,也就是說(shuō)可以通過(guò)字符串處理類中的成員或者對(duì)象中的屬性。下面是一個(gè)例子代碼:

    class Foo:def __init__(self,name,age):self.name=nameself.age=agedef show(self):return self.name,self.age obj=Foo("xiaoming",18) print(getattr(obj,"name")) setattr(obj,"k1","v1") print(obj.k1) print(hasattr(obj,"k1")) delattr(obj,"k1") show_fun=getattr(obj,"show") print(show_fun()) 執(zhí)行結(jié)果: xiaoming v1 True ('xiaoming', 18)

    反射/自省能夠直接訪問(wèn)以及修改運(yùn)行中的類和對(duì)象的成員和屬性,這是一個(gè)很強(qiáng)大的功能,并且并不像java中效率很低,所以用的很多。

    下面是一個(gè)反射/自省用在模塊級(jí)別的例子:

    import s2 operation=input("請(qǐng)輸入U(xiǎn)RL:") if operation in s2.__dict__:getattr(s2,operation)() else:print("404")#模塊s2中的代碼: def f1():print("首頁(yè)") def f2():print("新聞") def f3():print("精選") 執(zhí)行結(jié)果: 請(qǐng)輸入U(xiǎn)RL:f1 首頁(yè)

    6.單例模式

    這里介紹一個(gè)設(shè)計(jì)模式,設(shè)計(jì)模式在程序員寫了兩三年代碼的時(shí)候,到一定境界了,才會(huì)考慮到設(shè)計(jì)模式對(duì)于程序帶來(lái)的好處,從而使用各種設(shè)計(jì)模式,這里只是簡(jiǎn)單的介紹一個(gè)簡(jiǎn)單的設(shè)計(jì)模式:單例模式。在面向?qū)ο笾械膯卫J骄褪且粋€(gè)類只有一個(gè)對(duì)象,所有的操作都通過(guò)這個(gè)對(duì)象來(lái)完成,這就是面向?qū)ο笾械膯卫J?#xff0c;下面是實(shí)現(xiàn)代碼:

    class Foo: # 單例模式__v=None@classmethoddef ge_instance(cls):if cls.__v:return cls.__velse:cls.__v=Foo()return cls.__v obj1=Foo.ge_instance() print(obj1) obj2=Foo.ge_instance() print(obj2) obj3=Foo.ge_instance() print(obj3) 執(zhí)行結(jié)果: <__main__.Foo object at 0x000001D2ABA01860> <__main__.Foo object at 0x000001D2ABA01860> <__main__.Foo object at 0x000001D2ABA01860>

    可以看到,三個(gè)對(duì)象的內(nèi)存地址都是一樣的,其實(shí),這三個(gè)變量中存儲(chǔ)的都是同一個(gè)對(duì)象的內(nèi)存地址,這樣有什么好處呢?能夠節(jié)省資源,就比如在數(shù)據(jù)庫(kù)連接池的時(shí)候就可以使用單例模式,只創(chuàng)建一個(gè)類的對(duì)象供其他程序調(diào)用,還有在web服務(wù)中接收請(qǐng)求也可以使用單例模式來(lái)實(shí)現(xiàn),節(jié)省資源。

    總結(jié)

    以上是生活随笔為你收集整理的python进阶到高阶大全(强烈推荐)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。