为什么self.__dict__可以触发getattribute而instance.attribute不能?

问题描述 投票:0回答:1

证明验证了

self.__dict__
可以触发描述符中的
__getattribute__

class Room:
    def __init__(self,name):
        self.name = name
    def __getattribute__(self,key):
        print('in __getattribute__',key)
        return  object.__getattribute__(self,key)
    def __setattr__(self,attr,value):
        print('in __setattr__',attr)
        self.__dict__[attr] = value
        print('over')

创建一个实例,我在输出信息中添加一些以

#
开头的注释:

x = Room('r1')
# self.name = name in __init__ trigger __setattr__
in __setattr__ name  
# python interpreter read part of self.__dict__[attr] = value,extract self.__dict__ to trigger __getattribute__.
in __getattribute__ __dict__  
over

我们看到Python解释器可以提取整行字符串的一部分来触发

__getattribute__
方法。

class Sample:
    def __init__(self, name):
        self.name = name
    def __get__(self,instance,owner):
        print('get called')
    def __set__(self, instance, value):
        print('set called')

class Person:
    name = Sample('name')

举个例子:

p = Person()
p.name
get called

p.name
可以触发
__get__

p.name = 'tom'
set called

对于命令

p.name = 'tom'
,为什么Python解释器不提取
p.name
调用
__get__
然后让
p.name = 'tom'
调用
__set__
?为什么输出不是如下所示?

p.name = 'tom'
get called   # p.name  trigger
set called   # p.name = 'tom' trigger
python-3.x descriptor
1个回答
0
投票

Assignemts 将为普通对象触发

__setattr__
,并调用描述符中的
__set__
方法,如您所验证。

您的第一个示例运行

__getattribute__
来检索实例
__dict__
的唯一原因是因为 您的
__setattr__
的自定义实现会这样做。

默认的

__setattr__
通常会在实例
__dict__
中创建一个条目,但该条目将使用内部槽在本机代码中引用,并且不会通过
__gettattribute__
重定向。

您可以通过 callign

__setattr__
使用默认的
super()
实现来轻松验证这一点,而不是自己创建字典条目:

class Room:
    def __init__(self,name):
        self.name = name
    def __getattribute__(self,key):
        print('in __getattribute__',key)
        return  object.__getattribute__(self,key)
    def __setattr__(self,attr,value):
        print('in __setattr__',attr)
        super().__setattr__(attr, value)
        print('over')

在交互式翻译器中:

In [35]: r = Room("blah")
in __setattr__ name
over
In [36]: r.name
in __getattribute__ name
Out[36]: 'blah'

In [37]: r.__dict__
in __getattribute__ __dict__
Out[37]: {'name': 'blah'}

因此,您在描述符中的

__set__
中观察到的行为是普通行为。

© www.soinside.com 2019 - 2024. All rights reserved.