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
相关文章
相关标签/搜索