python-面向對象-19-object根類/weakref弱引用

1.object根類

object類是全部類的父類,所以全部的類都有object類的屬性和方法。咱們顯然有必要深刻研究一下object類的結構。對於咱們深刻學習Python頗有好處。
其實咱們在前面第17講介紹繼承的時候,其實就已經介紹object根類的一部分,包括使用mro()函數查看類的繼承關係,此次咱們從另外角度來講明object根類。python

仍是經過一個例子開始:git

class Person:
    count = 0
    
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_age(self):
        print("{0}的年齡是:{1}".format(self.name, self.age))

obj = object()
print(dir(obj))

s = Person("聶發俊", 100)
print(dir(s))

運行結果:github

['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'count', 'name', 'say_age']

程序說明:
這段程序已經很熟悉了,運行原理就不過多贅述了。咱們對比一下對象obj和對象s所返回的屬性列表,發現相比增長了一下幾個屬性:__dir__, __module__,__weakref__,age,count,name,say_age。首先說簡單的:markdown

  1. 實例屬性: name,age
  2. 類屬性:count
  3. 實例方法:say_age

2. __dir__屬性列表

只有存在類方法(靜態方法)、類屬性、實例屬性、實例方法中至少一項,纔會有__dict__屬性。如上面例子中的對象obj,就沒有__dict__屬性。ssh

3.__module__模塊屬性

表明當前對象運行的模塊ide

class Person:
    pass

p = Person()
print(p.__module__)

運行結果:函數

__main__

程序說明:默認運行在__main__模塊下。學習

4.__weakref__弱引用屬性

提及弱引用,就不得不說前面提到的Python垃圾回收機制,垃圾回收機制最核心的機制就是引用計數。weakref的弱引用是相對於引用計數而言的,引用計數的方式也能夠叫作常規引用或者強引用(後面我的定義,若是不對,請多多指教。)
相同點: 不管是常規引用仍是弱引用,都可以經過引用的方式獲取到被引用對象的地址,換句話說,就是能夠具備被引用對象的想用的操做
區別:常規引用會增長引用計數,可是弱引用不會增長引用對象this

默認狀況下是沒有弱引用的:code

class Person:
    pass

p = Person()
print(p.__weakref__)

運行結果:

None

程序說明:普通對象在默認狀況下是不存在弱引用的。

下面咱們就介紹一下弱引用常見的兩種形式

4.1 weakref.ref(p_object)方法

使用weakref.ref方法是最常規的方法,返回的是一個weakref類型對象,若是須要只用引用,須要經過()才能獲取到被引用對象。
示例代碼:

import weakref
import sys


class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age


def ref_callback(reference):
    print("ref_callback")
    print(reference, "this weak reference invalid")


p1 = Person("聶發俊", 100)
print(sys.getrefcount(p1))


# 使用weakref.ref方法構建弱引用
wek1 = weakref.ref(p1, ref_callback)
print(sys.getrefcount(p1))
print("--" * 20)

print(p1.__weakref__)
print(wek1)
print(wek1())
print("{0}的年齡是:{1}".format(wek1().name, wek1().age))

print('--' * 20)
del p1
print(wek1)

運行結果:

2
2
----------------------------------------
<weakref at 0x00000260D5978CC8; to 'Person' at 0x00000260BE779908>
<weakref at 0x00000260D5978CC8; to 'Person' at 0x00000260BE779908>
<__main__.Person object at 0x00000260BE779908>
聶發俊的年齡是:100
----------------------------------------
ref_callback
<weakref at 0x00000260D5978CC8; dead> this weak reference invalid
<weakref at 0x00000260D5978CC8; dead>

程序說明:

  1. 第一部分,兩部分的引用數目都是2(爲何是2,能夠看前面的垃圾回收機制),說明弱引用不會增長引用計數。
  2. 建立弱引用之後,被引用對象的__weakref__也有值了,指向和wek1同樣的地址。wek1是一個weakref類型的對象,只有使用wek1()的方式,才能獲取被引用對象__main__.Person,使用被引用對象的實例屬性,也須要帶上()
  3. 當刪除被引用對象是,會觸發構建弱引用的指定的回調函數ref_callback,同時wek1的弱引用狀態變成dead狀態。

4.2 weakref.proxy(p_object, callback)方法

使用weakref.proxy方法建立弱引用返回被引用對象,相似於a=b操做,這個是和使用ref函數不同的地方。
示例代碼:

import weakref
import sys


class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age


def proxy_callback(reference):
    print("proxy_callback call")


p1 = Person("聶發俊", 100)
print(sys.getrefcount(p1))


# 使用weakref.proxy方法構建弱引用
wek2 = weakref.proxy(p1, proxy_callback)
print(sys.getrefcount(p1))
print("--" * 20)

print(p1)
print(wek2)
print("{0}的年齡是:{1}".format(wek2.name, wek2.age))

print('--' * 20)
del p1
print(wek2)

運行結果:

2
2
----------------------------------------
<__main__.Person object at 0x0000010E9784F388>
<__main__.Person object at 0x0000010E9784F388>
聶發俊的年齡是:100
----------------------------------------
proxy_callback call
Traceback (most recent call last):
  File "test.py", line 30, in <module>
    print(wek2)
ReferenceError: weakly-referenced object no longer exists

程序說明:

  1. 引用計數的數目同上面的例子
  2. 使用weakref.proxy返回的被引用對象,p1wek2指向相同的地址0x000001EFF7219908,使用實例屬性不須要()
  3. 當刪除被引用對象p1,方法weakref.proxy指定的回調函數proxy_callback會被調用,注意由於被引用對象先被刪除,而後在執行回調函數,這個時候雖然有參數reference代指被引用對象,可是不能使用,由於已經被刪除了
  4. 這個時候打印wek2會提示錯誤信息,由於被引用對象p1被刪除了,沒法獲取對象

4.3 弱引用簡單總結

  1. weakref.ref()返回weakref,使用被引用對象須要使用()進行輔助,刪除被引用對象時,weakref狀態變成dead.
  2. weakref.proxy()返回被引用對象,能夠直接使用被引用對象,刪除被引用對象時,proxy不能再繼續使用,沒法再獲取被引用對象。
  3. 目前在實際開發中沒有使用到弱引用,具體使用場景等後面有具體使用場景再補充。

備註:
更多精彩博客,請訪問: 聶發俊的技術博客
對應視頻教程,請訪問: python400
完整markdown筆記,請訪問: python400_learn_github
相關文章
相關標籤/搜索