解释 __dict__ 属性

2025-03-10 08:49:00
admin
原创
43
摘要:问题描述:我对这个__dict__属性真的很困惑。我搜索了很多,但仍然不确定输出结果。有人可以从零开始解释一下这个属性的用法吗,当它在对象、类或函数中使用时?解决方案 1:基本上,它包含描述相关对象的所有属性。它可用于更改或读取属性。引用自文档__dict__用于存储对象(可写)属性的字典或其他映射对象。请记...

问题描述:

我对这个__dict__属性真的很困惑。我搜索了很多,但仍然不确定输出结果。

有人可以从零开始解释一下这个属性的用法吗,当它在对象、类或函数中使用时?


解决方案 1:

基本上,它包含描述相关对象的所有属性。它可用于更改或读取属性。引用自文档__dict__

用于存储对象(可写)属性的字典或其他映射对象。

请记住,在 Python 中一切都是对象。当我说一切时,我指的是函数、类、对象等一切(你没看错,是类。类也是对象)。例如:

def func():
    pass

func.temp = 1

print(func.__dict__)

class TempClass:
    a = 1
    def temp_function(self):
        pass

print(TempClass.__dict__)

将输出

{'temp': 1}
{'__module__': '__main__', 
 'a': 1, 
 'temp_function': <function TempClass.temp_function at 0x10a3a2950>, 
 '__dict__': <attribute '__dict__' of 'TempClass' objects>, 
 '__weakref__': <attribute '__weakref__' of 'TempClass' objects>, 
 '__doc__': None}

解决方案 2:

Python文档定义__dict__为:

用于存储对象(可写)属性的字典或其他映射对象。

但这个定义有点模糊,导致了很多错误的使用__dict__

确实,当您阅读这个定义时,您能分辨出什么是“可写”属性,什么不是“可写”属性吗?


示例

让我们举几个例子来说明它有多么令人困惑和不准确。

class A:

    foo = 1

    def __init__(self):
        self.bar = 2

    @property
    def baz(self):
        return self._baz

    @bar.setter
    def baz(self, value):
        self._baz = value

>>> a = A()
>>> a.foo
1
>>> a.bar
2

给定上述类A并了解__dict__的定义,你能猜出的值是多少吗a.__dict__

  • 是否foo具有可写属性a

  • 是否bar具有可写属性a

  • 是否baz具有可写属性a

  • 是否_baz具有可写属性a

答案如下:

>>> a.__dict__
{'bar': 2}

令人惊讶的是,foo没有显示。 事实上,尽管可以通过 访问a.foo,但它是类的属性A,而不是实例的属性a

现在,如果我们将其明确定义为的属性,会发生什么a

>>> a.foo = 1
>>> a.__dict__
{'bar': 2, 'foo': 1}

从我们的角度来看,实际上什么都没有改变,a.foo仍然等于1,但现在它出现在中__dict__。请注意,我们可以通过删除来继续使用它,a.foo例如:

>>> del a.foo
>>> a.__dict__
{'bar': 2}
>>> a.foo
1

这里发生的情况是,我们删除了实例属性,并且调用a.foo又回到了A.foo

现在我们来看看baz。我们可以假设我们找不到它,a.__dict__因为我们还没有给它赋值。

>>> a.baz = 3

好了,现在我们定义了a.baz。那么, 是baz可写属性吗? 那 呢_baz

>>> a.__dict__
{'bar': 2, '_baz': 3}

__dict__的角度来看,_baz是一个可写属性,但baz事实并非如此。再次解释, 是baz类的属性A,而不是实例的属性a

>>> A.__dict__['baz']
<property at 0x7fb1e30c9590>

a.baz`A.baz.fget(a)`仅仅是一个在幕后调用的抽象层。

让我们对我们的亲爱的朋友更加鬼鬼祟祟并挑战其“可写”的定义。

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__到底是什么呢?

由于注意到上述示例中的行为,我们现在可以更好地理解__dict__实际发生了什么。但我们需要从开发人员的视角切换到计算机的视角:

__dict__包含针对该特定对象存储在程序内存中的数据。

就是这样,__dict__公开了我们的对象地址中实际存储在内存中的内容。

Python数据模型文档也将其定义为对象的命名空间:

类实例具有以字典形式实现的命名空间,这是搜索属性引用的第一个位置。如果未在此处找到属性,而实例的类具有同名属性,则继续搜索类属性。

然而,我相信将其视为__dict__对象的内存表可以更好地直观地显示该命名空间中包含的内容和不包含的内容。

但是!有一个问题...


你以为我们已经完成了吗__dict__

__dict__并不是处理对象内存占用的方法,而是一种办法

确实还有另一种方法:__slots__。我不会在这里详细说明它的工作原理,如果您想了解更多信息,已经有一个非常完整的答案__slots__。但对我们来说重要的是,如果定义了插槽:

class C:
    __slots__ = ('foo', 'bar')

    def __init__(self):
        self.foo = 1
        self.bar = 2

>>> c = C()
>>> c.foo
1
>>> c.bar
2
>>> c.__dict__
AttributeError: 'C' object has no attribute '__dict__'

我们可以说“再见”了__dict__


那么我什么时候应该使用__dict__

正如我们所见,__dict__必须从计算机的角度来看待,而不是从开发人员的角度来看待。通常,我们认为的对象的“属性”与实际存储在内存中的内容没有直接联系。特别是使用属性或__getattr__例如,这会增加一个抽象级别以方便我们理解。

尽管在大多数情况下使用__dict__来检查对象的属性都是可行的,但我们不能 100% 地依赖它。这对于用于编写通用逻辑的东西来说是一种遗憾。

的使用案例__dict__可能应该仅限于检查对象的内存内容。这并不常见。请记住,__dict__在定义插槽时,可能根本没有定义(或缺少实际存储在内存中的某些属性)。

它在 Python 的控制台中也非常有用,可以快速检查类的属性和方法。或者对象的属性(我知道我刚才说过我们不能依赖它,但在控制台中,谁会在乎它有时会失败或者不准确)。


谢谢,但是...那么我该如何浏览我的对象的属性呢?

我们看到它__dict__经常被误用,我们不能真正依赖它来检查对象的属性。但是,正确的做法是什么呢?有没有办法从开发人员的抽象角度浏览对象的属性?

是的。有几种方法可以进行自省,正确的方法取决于您实际想要获得什么。实例属性、类属性、属性、私有属性,甚至方法……从技术上讲,所有这些都是属性,根据您的情况,您可能希望包含一些属性,但排除其他属性。上下文也很重要。也许您正在使用一个已经通过其 API 公开您想要的属性的库。

但一般情况下,你可以依赖该inspect模块。

class D:

    foo = 1
    __slots = ('bar', '_baz')

    @property
    def baz(self):
        return self._baz

    @baz.setter
    def baz(self, value):
        self._baz = value

    def __init__(self):
        self.bar = 2
        self.baz = 3

    def pointless_method(self):
        pass


>>> d = D()
>>> import inspect
>>> dict((k, v) for k, v in inspect.getmembers(d) if k[0] != '_')
{
 'bar': 2,
 'baz': 3,
 'foo': 1
}
>>> dict((k, getattr(d, k)) for k, v in inspect.getmembers(D) if inspect.isdatadescriptor(v) or inspect.isfunction(v))
{
 '__init__': <bound method D.__init__ of <__main__.D object at 0x7fb1e26a5b40>>,
 '_baz': 3,
 'bar': 2,
 'baz': 3,
 'pointless_method': <bound method D.pointless_method of <__main__.D object at 0x7fb1e26a5b40>>
}

解决方案 3:

dict可以以字典的形式获取对象中的实例变量(数据属性)。

因此,如果有Person以下类:

class Person:
    x1 = "Hello"
    x2 = "World"
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def test1(self):
        pass
        
    @classmethod
    def test2(cls):
        pass
    
    @staticmethod
    def test3():
        pass

obj = Person("John", 27)    
print(obj.__dict__) # Here

dict在字典中获取nameage

{'name': 'John', 'age': 27}

并且,如果在实例化之后添加新的实例变量,如下所示:gender

# ...

obj = Person("John", 27)
obj.gender = "Male" # Here
print(obj.__dict__)

dict获取和name,并将它们的值放入字典中,如下所示:age`gender`

{'name': 'John', 'age': 27, 'gender': 'Male'}

此外,如果使用dir()如下所示:

# ...

obj = Person("John", 27)
obj.gender = "Male" 
print(dir(obj)) # Here

我们可以将对象中的所有内容以列表形式获取,如下所示:

['__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', 'gender', 'name', 'test1', 'test2', 'test3', 'x1', 'x2']

而且,据我研究和提问, Python 中没有函数可以获取对象中的静态或特殊变量或普通、类、静态或特殊方法。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1887  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1425  
  在制造业数字化转型的进程中,PLM(产品生命周期管理)系统、ERP(企业资源计划)系统、MES(制造执行系统)以及 CAD(计算机辅助设计)软件都扮演着至关重要的角色。然而,这些系统和软件各自独立运行时,往往难以发挥出最大的协同效应。实现 PLM 系统与 ERP、MES、CAD 的有效集成,成为提升企业整体竞争力、优化...
plm系统的主要功能模块   3  
  产品生命周期管理(PLM)作为一种先进的管理理念和技术,在电子与半导体行业正发挥着日益重要的作用。随着电子与半导体行业的快速发展,产品更新换代速度加快,市场竞争愈发激烈,企业面临着诸多挑战,如缩短产品上市时间、提高产品质量、降低成本等。而PLM的应用为企业应对这些挑战提供了有效的解决方案,展现出巨大的应用价值。提升产品...
plm项目   4  
  PLM(产品生命周期管理)项目管理软件在现代企业的产品研发、生产与运营中扮演着至关重要的角色。它整合了从产品概念设计到退役的全流程数据与流程,助力企业提升效率、降低成本并增强创新能力。随着科技的飞速发展以及企业需求的不断演变,未来十年 PLM 项目管理软件的发展充满了无限可能,值得深入探讨与预测。智能化与自动化趋势智能...
plm产品全生命周期管理   6  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用