class B:
def __init__(self):
self.foobar = 'baz'
def __setattr__(self, name, value):
if name == 'foobar' and 'foobar' in self.__dict__:
# Allow the first definition of foobar
# but prevent any subsequent redefinition
raise TypeError("'foobar' is a read-only attribute")
super().__setattr__(name, value)
>>> b = B()
>>> b.foobar
'baz'
>>> b.foobar = 'bazbar'
TypeError: 'foobar' is a read-only attribute
>>> # From our developer's perspective, 'foobar' is not a writable attribute
>>> # But __dict__ doesn't share this point of view
>>> b.__dict__
{'foobar': 'baz'}
就是这样,__dict__公开了内存中对象地址处实际存储的内容。 data model上的Python文档也将其定义为对象的命名空间: 类示例有一个作为字典实现的命名空间,字典是搜索属性引用的第一个地方。当在字典中找不到属性,而示例的类有一个同名的属性时,搜索将继续类属性。 但是,我相信将__dict__看作对象的内存表可以更好地直观地显示此名称空间中包含了什么,不包含什么。
3条答案
按热度按时间50pmv0ei1#
基本上它包含了描述对象的所有属性,可以用来修改或读取属性。引用
__dict__
的文档用于存储对象(可写)属性的字典或其他Map对象。
记住,在Python中,所有的东西都是对象。当我说所有的东西时,我指的是所有的东西,比如函数、类、对象等等(你没看错吧,类。类也是对象)。例如:
意志输出
dz6r00yl2#
Python文档将
__dict__
定义为:用于存储对象(可写)属性的字典或其他Map对象。
然而,这个定义有点模糊,这导致了
__dict__
的许多错误用法。实际上,当你阅读这个定义时,你能分辨出什么是"可写"属性,什么不是吗?
让我们举几个例子来说明它是多么令人困惑和不准确。
给定上面的类
A
并知道__dict__
的定义,您能猜出a.__dict__
的值是什么吗?foo
是a
的可写属性吗?bar
是a
的可写属性吗?baz
是a
的可写属性吗?_baz
是a
的可写属性吗?答案如下:
令人惊讶的是,
foo
并没有出现,事实上,尽管可以通过a.foo
访问,但它是类A
的属性,而不是示例a
的属性。现在,如果我们将其显式定义为
a
的属性,会发生什么情况?从我们的Angular 来看,没有什么真正的改变,
a.foo
仍然等于1
,但现在它显示在__dict__
中。注意,我们可以通过删除a.foo
来继续使用它,例如:这里发生的事情是我们删除了instance属性,并且调用
a.foo
又回到了A.foo
。现在我们来看一下
baz
,我们可以假设在a.__dict__
中找不到它,因为我们还没有给它赋值。好了,现在我们定义了
a.baz
。那么,baz
是一个可写属性吗?_baz
呢?从
__dict__
的Angular 来看,_baz
是一个可写属性,但baz
不是,原因是baz
是类A
的属性,而不是示例a
的属性。a.baz
只是在幕后调用A.baz.fget(a)
的抽象层。让我们对我们亲爱的朋友更加狡猾,挑战它对"可写"的定义。
__dict__
到底是什么**多亏了上面例子中的行为,我们现在可以更好地理解
__dict__
实际上做了什么,但是我们需要从开发人员的Angular 切换到计算机的Angular :__dict__
包含存储在程序内存中用于此特定对象的数据。*就是这样,
__dict__
公开了内存中对象地址处实际存储的内容。data model上的Python文档也将其定义为对象的命名空间:
类示例有一个作为字典实现的命名空间,字典是搜索属性引用的第一个地方。当在字典中找不到属性,而示例的类有一个同名的属性时,搜索将继续类属性。
但是,我相信将
__dict__
看作对象的内存表可以更好地直观地显示此名称空间中包含了什么,不包含什么。__dict__
**__dict__
不是处理对象内存占用的方法,而是一种方法。的确有另一种办法:
__slots__
。我不会在这里详细说明它是如何工作的,如果你想了解更多,已经有a very complete answer about__slots__
了。但对我们来说重要的是,如果定义了插槽:我们可以对
__dict__
说再见了。__dict__
?**正如我们所看到的,
__dict__
必须从计算机的Angular 来看,而不是从开发人员的Angular 来看。通常情况下,我们所认为的对象的"属性"并不直接与内存中实际存储的内容相关联。特别是使用属性或__getattr__
时,这增加了一个抽象层,使我们感到舒适。虽然使用
__dict__
来检查对象的属性在大多数琐碎的情况下都可以工作,但是我们不能100%地依赖它,这对于用来编写泛型逻辑的东西来说是一个耻辱。__dict__
的用例应该仅限于检查对象的内存内容,但这并不常见。请记住,在定义插槽时,__dict__
可能根本没有定义(或者缺少实际存储在内存中的一些属性)。在Python的控制台中,快速检查一个类的属性和方法,或者一个对象的属性也是非常有用的(我知道我刚才说过我们不能依赖它,但是在控制台中,谁在乎它是否有时会失败,或者它是否准确)。
我们看到
__dict__
经常被误用,我们不能真正依靠它来检查对象的属性。但是,正确的方法是什么呢?有没有办法从开发人员的抽象Angular 来浏览对象的属性呢?是的。有几种方法可以做内省,正确的方法将取决于你实际上想要得到什么。示例属性、类属性、属性、私有属性,甚至方法,......从技术上讲,这些都是属性,根据你的情况,你可能想要包括一些而排除另一些。上下文也很重要。也许您正在使用的库已经通过其API公开了您想要的属性。
但总的来说,您可以信赖
inspect
module。w6mmgewl3#
**dict**可以获取对象中的示例变量(数据属性)作为字典。
因此,如果下面有
Person
类:**dict**获取
name
和age
,其值位于字典中,如下所示:并且,如果示例化后添加新示例变量
gender
,如下所示:**dict**获取
name
、age
和gender
,它们的值在字典中,如下所示:此外,如果使用dir(),如下所示:
我们可以将对象中的所有内容作为列表获取,如下所示:
而且,就我所研究的和我所问的this question而言,在Python中,没有函数可以只获取对象中的静态或特殊变量,或者普通、类、静态或特殊方法。