基礎(chǔ)
同所有的語(yǔ)言一樣,Python都有它定義類(lèi)型的方式,引入第三方庫(kù)的方式,輸入輸出等等基本操作。這些可以在這里查到。
閑話
import的時(shí)候會(huì)執(zhí)行模塊內(nèi)容,比如里面要是有print會(huì)輸出
用if __name__ == __main__來(lái)區(qū)分是否是主模塊,還只是非主模塊。
is 和 == 區(qū)別
is 用于判斷兩個(gè)變量引用對(duì)象是否為同一個(gè), ==用于判斷引用變量的值是否相等。
內(nèi)置函數(shù)參考一覽
字符串之中文處理“解決中文亂碼問(wèn)題”
#!/usr/local/bin/python
#encoding:utf-8 | #-*-coding:utf8-*- | coding:utf8
1. 簡(jiǎn)介
字符串的編碼是將人能看懂的字符轉(zhuǎn)化成只有機(jī)器能看懂的01機(jī)器碼,于是這里就牽扯了字符串的編碼問(wèn)題了。這個(gè)問(wèn)題為什么要單獨(dú)拿出來(lái)說(shuō)呢?那是因?yàn)樵诓煌木幋a的環(huán)境下,中文字符都可能亂碼,如果你的環(huán)境是`utf-8`的環(huán)境,而終端是`GBK`環(huán)境,那么兩個(gè)環(huán)境之一必將亂碼。這是一個(gè)比較頭疼的現(xiàn)象。存文件的時(shí)候也是,不同的編碼最終存的機(jī)器碼是不同的。
**注:**Python2中支持str和unicode,而Python3中**只支持**unicode。
2. 編碼的演變方式如下:
ASCII -> ISO-8859-1 -> GB2 -> GBK -> GB18030
#ASCII是一個(gè)字節(jié)編碼一個(gè)字符只支持英文名,
#ISO-8859是對(duì)ASCII的一個(gè)拓展,還是一個(gè)字節(jié)編碼一個(gè)字符,支持西歐的國(guó)家
#帶GB的都是支持中文的,兩字節(jié)編一個(gè)字,GB的互相兼容
unicode -> UTF-8 -> UTF-32
#之后的統(tǒng)一是unicode,但是存儲(chǔ)效率太低。
#對(duì)unicode進(jìn)行壓縮后是UTF-8和UTF-32。
3. 解決方案
import sys
print sys.stdin.encoding
print sys.stdout.encoding
x = raw_input(u'請(qǐng)輸入名字:'.encode(sys.stdout.encoding))
f = open('1.txt','w')
f.write(x.decode(sys.stdin.encoding).encode('utf-8'))
f.close()
#這樣子我們就讓文字在不同的環(huán)境能正確顯示。
#同時(shí)用解碼和編碼的方式把存下來(lái)的內(nèi)容按UTF-8的方式存儲(chǔ)下來(lái)了
變量作用域
1. LEGB原則
'''python的變量按照以下的順序進(jìn)行搜索
L(local):函數(shù)本地
E(enclose):任意上層的嵌套函數(shù)
G(global):全局作用域(模塊,文件內(nèi))
B(build-in):內(nèi)置作用域(夸文件)
'''
x = 10
def fun():
global x
x += 2
pass
#這樣子就在函數(shù)里面調(diào)用了函數(shù)外的變量
函數(shù)的嵌套和閉包
閉包:能夠保留函數(shù)定義時(shí)的環(huán)境信息
嵌套:內(nèi)部函數(shù)用了外部函數(shù)的變量,或者外部函數(shù)返回了內(nèi)部函數(shù)
def f(x):
y = 100
def inner(z):
return x * y + z
return inner
a10 = f(10)#在創(chuàng)建的時(shí)候,給f這個(gè)函數(shù)的x賦值了10
print(a10(29)) #在調(diào)用函數(shù)內(nèi)部函數(shù)inner輸出結(jié)果為1029
#這時(shí)候我們觀察到本來(lái)應(yīng)該在調(diào)用后消失的x的值,在下面一步調(diào)用中還是保留著的。
#這種情況我們稱(chēng)之為閉包,即在a10創(chuàng)建的時(shí)候保存了定義時(shí)的環(huán)境變量
#這種做法我們能夠更靈活的使用函數(shù)
生成器
生成器的定義為:能生成迭代器的東西
生成器表達(dá)式:
(expr for iter in iterable [if condition])
生成器函數(shù):
如果函數(shù)的返回值用的不是return而是yield則是生成器函數(shù),能用for函數(shù)使用。
def inc(n = 1):
while True:
yield n
n += 1
a = inc()
print(a.next())
#可以變相的認(rèn)為在yield的地方被打了一個(gè)端點(diǎn)。
#用yield放回的時(shí)候,函數(shù)的堆棧還在保存著沒(méi)有銷(xiāo)毀
Why yield?
當(dāng)一個(gè)函數(shù) f,f 返回一個(gè)結(jié)果,而這個(gè)結(jié)果是動(dòng)態(tài)計(jì)算出來(lái)的,同時(shí)這個(gè)結(jié)果如果很大。這個(gè)時(shí)候,我們希望每次調(diào)用這個(gè)函數(shù)并使用迭代器進(jìn)行循環(huán)的時(shí)候一個(gè)一個(gè)的得到每個(gè) list 元素而不是直接得到一個(gè)完整的結(jié)果來(lái)節(jié)省內(nèi)存,這個(gè)時(shí)候yield就很有用。
打個(gè)比方的話,yield有點(diǎn)像斷點(diǎn)。 加了yield的函數(shù),每次執(zhí)行到有yield的時(shí)候,會(huì)返回yield后面的值 并且函數(shù)會(huì)暫停,直到下次調(diào)用或迭代終止;
yield后面可以加多個(gè)數(shù)值(可以是任意類(lèi)型),但返回的值是元組類(lèi)型的。
具體怎么使用 yield 參考:Python yield 使用淺析
集合操作(這個(gè)在其他語(yǔ)言中不常見(jiàn)特此記錄)
1. Python中的集合分類(lèi)
set #可變集合
frozenset #不可變集合,能hash
2. 運(yùn)算
s | t #并集
s & t #交集
s - t #差集
s ^ t #對(duì)稱(chēng)差集,拋去相交的剩下的
s |= t #把t并入s
s < t #看s是否為t的子集
s > t #看s是否為t的超集,即t包含于s
s.isdisjoint(t) #看s和t是否有交集
然后以下是可變集合特有的操作
python s.add(item) s.clear() s.dicard(item) && s.remove(item) #都是刪除操作,如果不存在,remove會(huì)拋出異常,discard不會(huì)拋出異常 s.update(t) #和t對(duì)比,把沒(méi)有的追加進(jìn)來(lái) s.difference_update(t) #在s中刪除和t交集的部分
裝飾器
本質(zhì)是函數(shù)的嵌套調(diào)用
目的是不破壞原有的代碼的前提下,進(jìn)行調(diào)試
#運(yùn)行邏輯如下
#decorator(f)(*args,**kwargs)
@decorator
def f(): pass
#這個(gè)deorator可以換成任何名字
#decorator(name)(f)(*args,**kwargs)
@decorator(name)
def f():pass
#帶參數(shù)的函數(shù)
def log(func):
def wrapper(*args, **kwargs): #這么寫(xiě)是可以通配所有的函數(shù)
print('~'*40)
start = time.clock()
res = func(*args, **kwargs)
end = time.clock()
print('calling',func.__name__,args,kwargs)
print('start at',start,' end at',end)
return wrapper
#以上就是對(duì)裝飾器的定義
def logEx(name):
def wrapper(func):
def wrapper1(*args,**kwargs):
print('~'*40)
start = time.clock()
res = func(*args, **kwargs)
end = time.clock()
print(name,'calling',func.__name__,args,kwargs)
print('start at',start,' end at',end)
return wrapper1
return wrapper
@logEx('Tom')
@log
#裝飾器可以連續(xù)插入新的功能,不會(huì)影響原來(lái)的業(yè)務(wù)功能
def f(x,y):
return x+y
#這樣子返回的是測(cè)試者姓名,函數(shù)的輸入?yún)?shù),還有輸出的結(jié)果
列表和列表解析(常用的操作這里不說(shuō),僅記錄自己不太熟悉的操作)
1. 列表常用操作
append #加入元素
extend #合并列表
del #刪除
enumerate(iter) #返回一個(gè)迭代器,會(huì)返回索引和值
"""
example for enumerate
for (index, value) in enumerate(itr):
print index,value
"""
len #返回長(zhǎng)度
reversed #反置操作
sorted(x,key=abs) #排序操作,高度可定制
sum #求和操作
2. 列表解析
列表解析是根據(jù)一個(gè)列表生成一個(gè)新的列表,幾乎可以和for循環(huán)等價(jià),但是它的優(yōu)點(diǎn)為代碼緊湊。同時(shí)性能更好。
[expr for iter in iterable [if condition]]
"""
result = [i**2 for in x if i<0]
result = [i**2 if i<0 else i for in x]
"""
迭代器
- 可迭代對(duì)象(Iterable):
如果一個(gè)對(duì)象可以用for ... in ...的方式遍歷內(nèi)容,則其為可迭代 - 迭代器(Iterator):
遍歷可迭代對(duì)象內(nèi)容的方式 - itertools:
- permutations:排列
cite = itertools.permutations(x,3)
for c in cite:
print(c)
#對(duì)x里面的內(nèi)容進(jìn)行3個(gè)3個(gè)進(jìn)行排列
- combinations:組合
itertools.combinations(x,3)
#對(duì)x里面的內(nèi)容進(jìn)行3個(gè)3個(gè)進(jìn)行組合
- product:笛卡爾積
z = ['a','b','c']
y = range(1,4)
a = itertools.product(z,y)
for i in a:
print(i)
- repeat:重復(fù)
- chain:鏈接一組迭代器
#把多個(gè)迭代器塞在一起 itertools.chain(citer,piter,priter)
面向?qū)ο缶幊趟枷?/h2>
面向?qū)ο缶幊痰奶攸c(diǎn)
1. 封裝
相當(dāng)于一個(gè)黑匣子,功能的實(shí)現(xiàn)過(guò)程封裝了進(jìn)去。
2. 繼承
字面意思,就是從父類(lèi)中繼承了他們的功能。
3. 多態(tài)
繼承了不同的父類(lèi),雖然他們的是同一個(gè)類(lèi)但是由于繼承了不同的父類(lèi),呈現(xiàn)了不同的功能,呈現(xiàn)了多樣性。
類(lèi)的簡(jiǎn)單說(shuō)明
1. 經(jīng)典類(lèi)
2. 新式類(lèi)
`__new__`
`__super`
`__slot__`
類(lèi)的使用
class A:
pass
#不繼承任何類(lèi)
class B(object):
pass
#繼承的類(lèi)向上推最終為object的話,這個(gè)類(lèi)就是新式類(lèi)
class D(B):
pass
#如D類(lèi)也是新式類(lèi)
類(lèi)的定義
1. 屬性
class Chinese(Person):
nation = 'China'
def __init__(self, name):
self.__name = name
#self指的是這個(gè)類(lèi)自己,同理java和Cpp的this
#前后都有`__`的是已經(jīng)有的方法
#用self來(lái)操作的屬性是對(duì)類(lèi)里面的屬性進(jìn)行操作的。
#屬性前面有`__`的屬性是私有屬性,沒(méi)有的話是公有屬性
def msg(self):
print(self.name)
a = Chinses(myname) #這樣創(chuàng)建實(shí)例
a.__dict__ #來(lái)看有哪些屬性
a.nation = 'blabla' #這樣子來(lái)修改
a._Chinese__name = 'blabla'
#這個(gè)證明用`__`定義的私有屬性只是改了名字來(lái)保護(hù)屬性,但是其實(shí)是有規(guī)律的
相當(dāng)于一個(gè)黑匣子,功能的實(shí)現(xiàn)過(guò)程封裝了進(jìn)去。
字面意思,就是從父類(lèi)中繼承了他們的功能。
繼承了不同的父類(lèi),雖然他們的是同一個(gè)類(lèi)但是由于繼承了不同的父類(lèi),呈現(xiàn)了不同的功能,呈現(xiàn)了多樣性。
`__new__`
`__super`
`__slot__`
class A:
pass
#不繼承任何類(lèi)
class B(object):
pass
#繼承的類(lèi)向上推最終為object的話,這個(gè)類(lèi)就是新式類(lèi)
class D(B):
pass
#如D類(lèi)也是新式類(lèi)
class Chinese(Person):
nation = 'China'
def __init__(self, name):
self.__name = name
#self指的是這個(gè)類(lèi)自己,同理java和Cpp的this
#前后都有`__`的是已經(jīng)有的方法
#用self來(lái)操作的屬性是對(duì)類(lèi)里面的屬性進(jìn)行操作的。
#屬性前面有`__`的屬性是私有屬性,沒(méi)有的話是公有屬性
def msg(self):
print(self.name)
a = Chinses(myname) #這樣創(chuàng)建實(shí)例
a.__dict__ #來(lái)看有哪些屬性
a.nation = 'blabla' #這樣子來(lái)修改
a._Chinese__name = 'blabla'
#這個(gè)證明用`__`定義的私有屬性只是改了名字來(lái)保護(hù)屬性,但是其實(shí)是有規(guī)律的
類(lèi)屬性:
這個(gè)是類(lèi)本身的屬性,在創(chuàng)建實(shí)例的時(shí)候不需要單獨(dú)在實(shí)例分配內(nèi)存的屬性。如上述例子中的nation屬性。如果修改了類(lèi)的這個(gè)屬性,那么所有用這個(gè)類(lèi)創(chuàng)建的實(shí)例中的這個(gè)屬性都會(huì)被更改。
實(shí)例屬性:
在__init__初始函數(shù)中定義的屬性是實(shí)例屬性。這個(gè)屬性是在類(lèi)創(chuàng)建實(shí)例的時(shí)候生成的屬性,這個(gè)是要單獨(dú)分配內(nèi)存的,而不是類(lèi)本身就有的屬性。
2. 屬性的可見(jiàn)性
在其他語(yǔ)言如`Cpp`和`Java`中都有特定的結(jié)構(gòu)如`private`和`protected`來(lái)定義,但是python其實(shí)是沒(méi)有底層對(duì)他們進(jìn)行實(shí)現(xiàn)的,所以python的共有屬性和私有屬性**是偽的**,所有的都可以用`__dict__`方式進(jìn)行查到的。
**公有屬性**
**私有屬性 **:
我們?cè)趯傩郧凹觍_`或者`__`來(lái)標(biāo)記這個(gè)是私有屬性。
- `__`定義的屬性:
是會(huì)被python**通過(guò)改名換姓的方式進(jìn)行保護(hù)。**
- `_`定義的屬性:
只是**形式上的私有屬性**,提醒你這個(gè)是私有屬性不要嘗試去直接訪問(wèn)它。
3. 訪問(wèn)屬性
直接訪問(wèn):
這個(gè)不是一個(gè)好的方式,因?yàn)檫`背了封裝性。壞處是如果類(lèi)的屬性名稱(chēng)進(jìn)行了更改,那所有直接訪問(wèn)這個(gè)屬性的代碼都需要更改。
定義get,set方法:
這個(gè)方法就是Cpp和Java中常用的方法。
通過(guò)屬性裝飾器
- @property:屬性的查看
- @***.setter:屬性的寫(xiě)入
- @***.deleter:屬性的刪除
class Chinese(Person):
nation = 'China'
def __init__(self, id, name):
self.__name = name
self.__id = id
slef.__email = None
def getID(self):
print(self.__id)
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
self.__name = name
@name.deleter
def name(self):
del self.name
VDeamoV = Chinese(1,'VDeamoV')
print(VDeamoV.getID())
VDeamoV.name = 'Other Name'
print(VDeamoV.name)
#這里替換了并輸出了保護(hù)的屬性,但是沒(méi)有用類(lèi)中的名字
這個(gè)好處就是,使用的人調(diào)用的時(shí)候看起來(lái)就像函數(shù)調(diào)用的感覺(jué),而不是調(diào)用函數(shù)的感覺(jué)。
4. 通過(guò)描述符訪問(wèn)
編寫(xiě)類(lèi)的時(shí)候,如果類(lèi)滿足了__get__、__set__和__del__這三個(gè)方法就可以稱(chēng)之為描述符。
描述符的兩個(gè)目的:
- 代碼重用
- 描述符屬性必須定義成類(lèi)屬性
class Property(object):
def __init__(self, propname, datatype, default = None):
self._name ='_' + propname + '_'
#這個(gè)在最終在實(shí)例中的屬性是什么名字
self._type = datatype
self._default = default if default else self._type()
def __get__(self, instance, owner):
return getattr(instance, self._name, self._default)
#getattr是python內(nèi)置的獲取屬性的值,如果沒(méi)有是缺省值
pass
def __set__(self, instance, value):
if not isinstance(value, self._type):
raise TypeError('TypeError, must be %s type0' self._type)
#isinstance()是判斷是不是一個(gè)類(lèi)型的,raise是拋出異常
setattr(instance, self._name, value)
#只有這個(gè)執(zhí)行之后,才會(huì)真的在實(shí)例中創(chuàng)建屬性
pass
def __del__(self):
pass
class Email(Property):
def __init__(self, propname, default = None):
pass
def __set__(self, instance, value):
pass
class Chinese(object):
ID = Property('id', int)
Name = Property('name', str)
Email = Email('email')
def __init__(self, id, name, email):
self.ID = id
self.Name = name
self.Email = email
VDeamoV = Chinese() #這時(shí)候創(chuàng)建Chinese類(lèi)的時(shí)候沒(méi)有任何屬性
VDeamoV.ID = 123
VDeamoV.Name = 'test'
VDeamoV.Email = 'asd@bupt.edu.cn'
類(lèi)的方法
1. 實(shí)例方法
- 第一個(gè)參數(shù)是self
2. 類(lèi)方法
@classmethod- 第一個(gè)參數(shù)是
cls,綁定到類(lèi)
這個(gè)cls也是它和靜態(tài)方法的區(qū)別,它可以直接用cls來(lái)調(diào)用自己的類(lèi)本身而不是向靜態(tài)方法一樣將返回的類(lèi)寫(xiě)死,很大的區(qū)別會(huì)體現(xiàn)在繼承類(lèi)的時(shí)候返回的類(lèi)的類(lèi)型,見(jiàn)下方例子的注釋說(shuō)明
注意:
Python不支持多態(tài),即不支持函數(shù)名字相同但是變量不同,但是Cpp支持。
3. 靜態(tài)方法
@staticmethod- 和普通函數(shù)一樣,無(wú)綁定
4. 特殊方法
- 一些內(nèi)置的如
__init__這些函數(shù)。
class Test():
def Hi(self):
pass
#實(shí)例方法
#中間略
@staticmethod
def getPeopleByParents(father, mother):
print(father, mother)
return Chinese(10,'father'+'_son','mother'+'_son')
#靜態(tài)方法
@classmethod
def getPeopleBySibling(cls, sibling):
print sibling
return cls(10, 'TestName', 'blabla')
#類(lèi)方法
class Test2(Test):
pass
a = Test2.getPeopleByParents('blabla', 'blablabla')
b = Test2.getPeopleBySibling('blabls')
#這時(shí)候a類(lèi)的類(lèi)型為Chinese,而b類(lèi)的類(lèi)型為T(mén)est2
運(yùn)算符重載
1. 構(gòu)造函數(shù)、析構(gòu)函數(shù)
-
__new__:和__init__的區(qū)別在它是在創(chuàng)建內(nèi)存空間的時(shí)候調(diào)用 -
__init__:是在初始化的時(shí)候才會(huì)調(diào)用 -
__del__:刪除或者回收的時(shí)候調(diào)用的函數(shù)
2. 四則運(yùn)算
__add____sub____mul____div__
3. 比較
__lt____gt____cmp__
4. 其他
__str____repr____contains____contains____bool__
class Test():
def __str__(self):
return "Here is the Return"
def __repr__(self):
return "ReprTest"
def __add__(self, other):
return self.ID + other.ID
def __lt__(self, other):
return self.ID < other.ID
a = Test()
print(a) #得到的結(jié)果是"Here is the Return"這個(gè)函數(shù)
a
#直接敲入對(duì)象名稱(chēng)的時(shí)候輸出的內(nèi)容由repr來(lái)決定
繼承
定義:根據(jù)已有的類(lèi)生成新的類(lèi)
目的:代碼重用、多態(tài)
class A(object):
def __init__(self):
print("In class A")
pass
class B(A):
pass
b = B()
#這個(gè)在構(gòu)造類(lèi)B的時(shí)候繼承了類(lèi)A,所以會(huì)執(zhí)行類(lèi)A構(gòu)造的時(shí)候的__init__
#不過(guò)如果類(lèi)B自身有__init__的話,就相當(dāng)于對(duì)類(lèi)A中的__init__進(jìn)行了重載
#針對(duì)第二行注釋說(shuō)的情況如果我們還想使用A的__init__可以用A.__init__的方式
1. 菱形繼承
多重繼承中出現(xiàn)的問(wèn)題,當(dāng)出現(xiàn)菱形的多重繼承的時(shí)候,函數(shù)名解析的問(wèn)題
- 經(jīng)典類(lèi):深度優(yōu)先
- 新式類(lèi):廣度優(yōu)先
解決這種情況的方案就是使用class A(object): def __init__(self): print("In class A") pass class B(A): def __init__(self): A.__init__(self) print("In B") class C(A): def __init__(self): A.__init__(self) print("In C") class D(B,C): def __init__(self): B.__init__(self) C.__init__(self) print("In D") pass d = D() #由于繼承的時(shí)候,有兩個(gè)相同名字的函數(shù),到底會(huì)繼承哪個(gè) #在執(zhí)行的時(shí)候,我們會(huì)發(fā)現(xiàn)這么調(diào)用父函數(shù)的話,A類(lèi)會(huì)被執(zhí)行2遍 #這樣子的話可能會(huì)出現(xiàn)問(wèn)題super
調(diào)用父類(lèi)的函數(shù)的時(shí)候,推薦都適用super調(diào)用,這樣子不容易出現(xiàn)問(wèn)題。但是class A(object): def __init__(self): print("In class A") pass class B(A): def __init__(self): #A.__init__(self) super(B,self).__init__() print("In B") class C(A): def __init__(self): #A.__init__(self) super(C,self).__init__() print("In C") class D(B,C): def __init__(self): #B.__init__(self) #C.__init__(self) super(D,self).__init__() print("In D") passsuper只支持新式類(lèi)。
2. inspect.getmro(class)
在1中我們知道了,同名函數(shù)繼承和調(diào)用的時(shí)候是有一個(gè)查找順序的,除了死記住一個(gè)固有的順序,我們還可以用`inspect`包中的`getmtro`函數(shù)。
```python
import inspect
inspect.getmro(D)
```
多線程和多進(jìn)程
線程和進(jìn)程的定義
可以參考王道考研操作系統(tǒng)的線程和進(jìn)程的定義。
1. 進(jìn)程具有獨(dú)立功能的程序
進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。
2. 進(jìn)程擁有獨(dú)立的地址空間
一個(gè)進(jìn)程崩潰后,不會(huì)對(duì)其他進(jìn)程產(chǎn)生影響。線程沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉等于整個(gè)進(jìn)程死掉。所以多進(jìn)程的程序比多線程的程序魯棒性要好。
3. GIL和多線程
- Global Interpreter Lock
- CPU密集型
因?yàn)槭羌俚亩嗑€程,所以CPU其實(shí)沒(méi)有啟動(dòng)多個(gè)CPU去運(yùn)行這些線程,所以效果不是很好。 - IO密集型
雖然在CPU分配的方面,線程的優(yōu)勢(shì)其實(shí)是沒(méi)有得到很好的效果,但是進(jìn)程的概念中,還是解決了IO交互速度和CPU運(yùn)算速度不匹配的問(wèn)題。所以在這種情況下使用多線程還是有意義的。
- CPU密集型
多線程模塊
1. thread模塊:便底層
2. threading模塊:
相對(duì)高層,提供RLock, Lock等同步機(jī)制。
threading的實(shí)現(xiàn)細(xì)節(jié)
繼承threading.Thread,實(shí)現(xiàn)run()方法。
-
join():掛起當(dāng)前線程,直到被調(diào)用線程結(jié)束 -
start():?jiǎn)?dòng)線程,執(zhí)行run中的代碼 -
is.Alive():判斷線程是否已經(jīng)結(jié)束。
線程中的鎖
threading.Lockthreading.RLock-
acquire():申請(qǐng)鎖 -
release():釋放鎖
import threading
class A(threading.Thread):
def __init__(self, n):
threading.Thread.__init__(self)
#一定要引入這個(gè)父類(lèi)的初始化
self._n = n
def run(self):
while True:
print('in thread %s' % self._n)
time.sleep(1)
pass
if __name__ == '__main__':
mt = [A(i) for i in range(4)]
for t in mt:
t.start()
for t in mt:
t.join()
#運(yùn)行結(jié)果會(huì)出現(xiàn)一行多個(gè)'in thread',
#原因是,多個(gè)線程打印的結(jié)果被同時(shí)扔進(jìn)了輸出緩存區(qū),
#這樣可以看出print操作其實(shí)不是一個(gè)原子操作
CPU密集的實(shí)例
from faker import Factory
faker =. Factroy.create()
cnt = 10000
x1 = [faker.paragraph() for i in range(cnt)]
x2 = [faker.paragraph() for i in range(cnt)]
import time
start = time.clock()
for one in x1:
len(one)
for one in x2:
len(one)
end = time.clock()
print('time: %s' % (end - start))
import threading
class A(threading.Thread):
def __init__(self, x):
threading.Thread.__init__(self)
self.x = x
def run(self):
for each in self.x:
len(each)
t1 = A(x1)
t2 = A(x2)
start1 = time.clock()
t1.start()
t2.start()
t1.join()
t2.join()
##等t1,t2都完成了才記錄
end1 = time.clock()
print("Thread time: %s" % (end1 - start1))
隨著數(shù)據(jù)的加大,(CPU密集操作的)單線線程的版本反而顯著優(yōu)于多線程
多進(jìn)程
- 多個(gè)python進(jìn)程 = 多個(gè)GIL鎖
- multiprocessing模塊
在python中,多進(jìn)程的使用是可以充分利用多核CPU,但是進(jìn)程的切換的開(kāi)銷(xiāo)往往是非常大的。
multiprocessing.Process的細(xì)節(jié)實(shí)現(xiàn)
-
join():掛起當(dāng)前進(jìn)程,直到被調(diào)用進(jìn)程結(jié)束。 -
start():?jiǎn)?dòng)進(jìn)程,執(zhí)行run中的代碼
進(jìn)程間的通信
- 進(jìn)程的內(nèi)存空間是獨(dú)立的,所以是沒(méi)有鎖的概念。
- 通過(guò)multiprocessing.Queue實(shí)現(xiàn)通信
Queue.put()Queue.get()
import multiprocessing
class A(multiprocessing.Process):
def __init__(self, n):
multiprocessing.Process.__init__(self)
#一定要引入這個(gè)父類(lèi)的初始化
self._n = n
def run(self):
while True:
print('in processing %s' % self._n)
time.sleep(1)
pass
if __name__ == '__main__':
mt = [A(i) for i in range(4)]
for t in mt:
t.start()
for t in mt:
t.join()
#這個(gè)時(shí)候在進(jìn)程里面看,會(huì)發(fā)現(xiàn)出現(xiàn)了5個(gè)進(jìn)程
進(jìn)程的通信案例,生產(chǎn)者和消費(fèi)者
import multiprocessing
import time
class Producer(multiprocessing.Process):
def __init__(self, q):
multiprocessing.Process.__init__(self)
self._q = q
def run(self):
while True:
self._q.put('Time is %s' % time.time())
pass
clas Consumer(multiprocessingl.Process):
def __init__(self, q, n):
multiprocessing.Process.__init__(self)
self._q = q
self._n = n
def run(self):
while True:
msf = None
try:
msg = self._q.get()
except:
time.sleep(1)
continue
if msg:
print('in consumer %s' % (self._n,msg))
pass
if __name__ == '__main__':
q = multiprocessing.Queue()
producer = Producer(q)
c1 = Consumer(q, 1)
c2 = Cousumer(q, 2)
producer.start()
c1.start()
c2.start()
結(jié)語(yǔ)
此次的Python個(gè)人總結(jié),由于Python的教程實(shí)在非常多,盡量省去了那些耳熟能詳?shù)奶貏e容易就能學(xué)會(huì)的內(nèi)容,如循環(huán)和創(chuàng)建函數(shù)類(lèi)等等。本文挑選的為就目前個(gè)人而言,覺(jué)得對(duì)于初學(xué)者比較不常用且重要的內(nèi)容進(jìn)行記錄。內(nèi)容的整理來(lái)自于目前自身報(bào)名的網(wǎng)課“北風(fēng)網(wǎng)”的課程學(xué)習(xí),不過(guò)目前不是很推薦大家去學(xué)。
最后,文章內(nèi)容有點(diǎn)雜亂,希望能得到大家諒解。