1. 程式人生 > >Python的進階篇(GIL, 深拷貝和淺拷貝, 多繼承和MRO順序, property屬性, with和上下文管理器)

Python的進階篇(GIL, 深拷貝和淺拷貝, 多繼承和MRO順序, property屬性, with和上下文管理器)

1、GIL(Global Interpreter Lock):

  全域性直譯器鎖就是CPython直譯器內部的鎖,與Python語言是沒有關係的。是直譯器為了鎖住解釋其內部的全域性資源,每個執行緒想要執行,首先要獲取GIL,而GIL本身就是一把互斥鎖,造成所有執行緒只能一個一個併發交替執行。

1.1、GIL被釋放的三種情況:

當前執行緒執行完 當前執行緒執行阻塞操作時會自動釋放,如I/O操作,所以多執行緒爬取比單執行緒爬取效能有提升,因為遇到IO阻塞會自動釋放GIL鎖。 當前執行緒執行超時(Python3使用計時器,當時間達到閾值時會釋放)的時候被釋放 結論:

適用於 I/O密集型程式<多執行緒效率比單執行緒高> 不適於 CPU密集型程式<多執行緒效率比單執行緒低>

1.2、區分CPython直譯器的GIL鎖和執行緒中的互斥鎖:

  GIL是直譯器層面的,只有CPython直譯器有,其他解釋沒有。而互斥鎖是python語言層面的鎖。CPython直譯器有GIL鎖,但是Python語言中執行緒互斥鎖還是被需要的,只有GIL鎖是無法對全域性資源進行安全的保護。主要原因是GIL在當前執行緒沒執行完有可能被釋放。

2、賦值-淺拷貝-深拷貝

2.1、賦值

  物件之間的賦值本質是物件之間的地址引用的傳遞。也就是多個物件指向同一個記憶體空間。

2.2、淺拷貝

  淺拷貝是對一個物件頂層資料的拷貝。

2.3、深拷貝

  深拷貝是對一個物件所有層次的拷貝(遞迴)

2.4、拷貝的其他方式

        切片表示式,可以複製一個序列         字典的copy方法可以拷貝一個字典   這兩種方式的拷貝都屬於淺拷貝。

2.5、注意點

淺拷貝對不可變型別和可變型別的copy不同。

copy.copy對可變型別進行淺拷貝。 copy.copy和copy.deepcopy對不可變型別的拷貝沒有意義。

3、import匯入模組

匯入指定目錄下的的模組:

將模組所在的路徑在程式中新增到sys.path列表中,該方法靈活,但是終端重啟後需要重新新增路徑。 修改作業系統的PYTHON_PATH環境變數 export PYTHON_PATH=$PYTHON_PATH:路徑 import A 和 from A import B 的區別

import A在當前作用域建立一個A物件<儲存模組物件的引用> from A import B 在當前作用域建立一個B<儲存A模組物件的B的引用>   可變型別的模組物件屬性兩種方式都可以修改,不可變型別的模組物件屬性,import A可以修改,而form A import B不可修改。

3、多繼承及MRO順序

3.1、多繼承

  在子類初始化的時候需要手動呼叫父類的初始化方法進行父類的屬性的構造,不然就不能使用提供的屬性。

       父類名.init()        super(cls, self).init()

3.2、MRO順序

MRO順序的意義:把所有類全部對映到這條線性結構上 保證所有類在該順序上都只出現一次。 super的意義:使用MRO順序呼叫 每一個類 ; 保證每個類都只調用一次<初始化一次> 查詢當前類在MRO順序中下一個類 引數1是當前類 引數2是例項物件。 檢視MRO順序:print(物件.__ mro __)或者(物件.mro())前者返回元組,後者返回列表。

4、property屬性

4.1、使用property的好處

   如果不加property屬性,物件的屬性不加訪問許可權,使用者可以用物件.屬性方便的修改,但是,不限制對屬性的修改會造成資料異常或錯誤;要是物件的屬性設定許可權,使用者操作起來比較複雜;使用property屬性後用戶操作更簡單、安全。

4.2、property屬性的功能

Python的property屬性的功能是:   property的作用就是 將一個屬性的操作方法封裝為一個屬性,使用者用起來就和操作普通屬性完全一致,非常簡單。

4.3、property屬性的設定

方法一:

class Person(object):
    def __init__(self, name, age):
        self.name = name 
        self.__age = age
    
    @property
    def age(self):
        return self.__age
        
    @age.setter
    def age(self, age):
        self.__age = age
    
    @age.deleter
    def age(self):
        del slef.__age
        print("已刪除")
        
        
person = Person
 
print(person.age)   # 列印當前年齡 '物件.age'
person.age = 111      # 通過  '物件.age = '  可以直接修改
print(person.age)   # 111
del person.age     # "已刪除"

方法二

# property屬性設定:x = property(get_x, set_x, del_x, "doc")
 
class Person(object):
    def __init__(self, name, age):
        self.name = name 
        self.__age = age
    
    def get_age(self):
        return self.__age
        
    def set_age(self, age):
        self.__age = age
 
    def del_age(self):
        del slef.__age
        print("已刪除")
    
    age = property(get_age, set_age, del_age, "describ")
    
person = Person(18)
 
print(person.age)   # 列印age  
person.age = 111    # 設定年齡為111
print(person.age)   # 驗證 111
desc = Person.age.__doc__  # 注意這裡Person是類物件,前面的person都是例項物件
print(desc)  # 列印describe
del person.age   # 已刪除

5、魔法屬性

5.1、__ doc __

表示類的描述資訊

class Foo(oject):
"""描述類資訊,這是個與魚人類"""
    pass
    
print(Foo.__doc__)   # 描述類資訊,這是個與魚人類

5.2、__ init __ 構造方法,初始化方法,通過類建立物件時,自動觸發

5.3、__ del __ 當例項物件被釋放時,自動觸發(臨終遺言)

5.4、__ call __ 當例項物件後面加上括號是,自動觸發(裝飾器類)

5.5、__ str __ 例項物件的返回值,當列印時,就可以看到

5.6、__ dict __ 類物件和例項物件中的所有屬性返回字典

6、with與“上下文管理器”

6.1、使用with的好處

上下文管理器本質就是能夠支援with操作

任何實現了 enter() 和 exit() 方法的物件都可稱之為上下文管理器,上下文管理器物件可以使用 with 關鍵字。

enter() 方法返回資源物件,,exit() 方法處理一些清除工作。

6.2、定義實現上下文管理器的類

class OpenFile(object):
    def __init__(self, file_name, file_model):
        self.file_name = file_name
        self.file_model = file_model
 
    def __enter__(self):
        """上文---提供資源"""
        print("正在進入上文")
        self.file = open(self.file_name, self.file_model)
        return self.file
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        """下文----關閉資源"""
        print("正在進入下文")
        self.file.close()
 
 
with OpenFile("log.txt", "r") as file:
    file_data = file.read(10)
    print(file_data)

6.3、通過contextmanager裝飾器更方便的實現上下文管理器

from contextlib import contextmanager
 
@contextmanager
def open_file(file_name, file_model):
    print("進入上文")
    f = open(file_name, file_model)
    yield f
    print("進入下文")
    f.close()
 
 
with open_file("log.txt", "r") as f:
    while True:
        f_data = f.read(10)
        if f_data:
            print(f_data)
        else:
            break