python個(gè)人總結(jié)

基礎(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ī)律的

類(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è)方法就是CppJava中常用的方法。

通過(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
    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")
        pass
    
    調(diào)用父類(lèi)的函數(shù)的時(shí)候,推薦都適用super調(diào)用,這樣子不容易出現(xiàn)問(wèn)題。但是super只支持新式類(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)題。所以在這種情況下使用多線程還是有意義的。

多線程模塊

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.Lock
  • threading.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)程

  1. 多個(gè)python進(jìn)程 = 多個(gè)GIL鎖
  2. multiprocessing模塊
    在python中,多進(jìn)程的使用是可以充分利用多核CPU,但是進(jìn)程的切換的開(kāi)銷(xiāo)往往是非常大的。

multiprocessing.Process的細(xì)節(jié)實(shí)現(xiàn)

  1. join():掛起當(dāng)前進(jìn)程,直到被調(diào)用進(jìn)程結(jié)束。
  2. start():?jiǎn)?dòng)進(jìn)程,執(zhí)行run中的代碼

進(jìn)程間的通信

  1. 進(jìn)程的內(nèi)存空間是獨(dú)立的,所以是沒(méi)有鎖的概念。
  2. 通過(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)雜亂,希望能得到大家諒解。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容