【问题标题】:Why don't instances of `xml.etree.ElementTree.Element` have `__dict__`?为什么`xml.etree.ElementTree.Element`的实例没有`__dict__`?
【发布时间】:2021-07-18 16:12:26
【问题描述】:
from xml.etree.ElementTree import Element
e = Element(None)
e.__dict__

->AttributeError: 'xml.etree.ElementTree.Element' object has no attribute '__dict'

将 C:\Python39\Lib\xml\etree\ElementTree.py 复制到其他地方:

from ElementTree import Element as Element2
e2 = Element2(None)
e2.__dict__

->{'tag': None, 'attrib': {}, '_children': []}

【问题讨论】:

    标签: python-3.x


    【解决方案1】:

    xml.etree.ElementTree 有一个optimised C implementation which replaces the Python implementation if available

    # Import the C accelerators
    try:
        # Element is going to be shadowed by the C implementation. We need to keep
        # the Python version of it accessible for some "creative" by external code
        # (see tests)
        _Element_Py = Element
    
        # Element, SubElement, ParseError, TreeBuilder, XMLParser, _set_factories
        from _elementtree import *
        from _elementtree import _set_factories
    except ImportError:
        pass
    else:
        _set_factories(Comment, ProcessingInstruction)
    

    值得注意的是,C 扩展类型通常没有__dict__ 插槽。通过复制类的 Python 实现而不加载 C 实现,可以使用原始 Python 实现。

    >>> from xml.etree.ElementTree import _Element_Py
    >>> e = _Element_Py(None)
    >>> e.__dict__
    {'tag': None, 'attrib': {}, '_children': []}
    

    【讨论】:

      【解决方案2】:

      This answer 很好地解释了__dict__ 属性:

      Python 对象将它们的实例变量存储在属于该对象的字典中。 vars(x) 返回这个字典(和 x.__dict__ 一样)。另一方面,dir(x) 返回 x 的“属性、其类的属性以及递归其类的基类的属性”的字典。

      让我们在实践中看看:

      import xml.etree.ElementTree as ET
      
      e = ET.Element(None)
      print(e.__dict__)
      # Raises AttributeError: 'xml.etree.ElementTree.Element' object has no attribute '__dict__'
      

      但是为什么,既然e 确实有属性呢?

      import xml.etree.ElementTree as ET
      
      e = ET.Element(None)
      print(e.tag)
      # Outputs None
      
      e = ET.Element("my-tag")
      print(e.tag)
      # Outputs my-tag
      

      让我们看看它的类的属性:

      import xml.etree.ElementTree as ET
      
      print(ET.Element.__dict__)
      

      这将输出

      mappingproxy({'__copy__': <method '__copy__' of 'xml.etree.ElementTree.Element' objects>,
                    '__deepcopy__': <method '__deepcopy__' of 'xml.etree.ElementTree.Element' objects>,
                    '__delitem__': <slot wrapper '__delitem__' of 'xml.etree.ElementTree.Element' objects>,
                    '__doc__': None,
                    '__getattribute__': <slot wrapper '__getattribute__' of 'xml.etree.ElementTree.Element' objects>,
                    '__getitem__': <slot wrapper '__getitem__' of 'xml.etree.ElementTree.Element' objects>,
                    '__getstate__': <method '__getstate__' of 'xml.etree.ElementTree.Element' objects>,
                    '__init__': <slot wrapper '__init__' of 'xml.etree.ElementTree.Element' objects>,
                    '__len__': <slot wrapper '__len__' of 'xml.etree.ElementTree.Element' objects>,
                    '__new__': <built-in method __new__ of type object at 0x92a480>,
                    '__repr__': <slot wrapper '__repr__' of 'xml.etree.ElementTree.Element' objects>,
                    '__setitem__': <slot wrapper '__setitem__' of 'xml.etree.ElementTree.Element' objects>,
                    '__setstate__': <method '__setstate__' of 'xml.etree.ElementTree.Element' objects>,
                    '__sizeof__': <method '__sizeof__' of 'xml.etree.ElementTree.Element' objects>,
                    'append': <method 'append' of 'xml.etree.ElementTree.Element' objects>,
                    'attrib': <attribute 'attrib' of 'xml.etree.ElementTree.Element' objects>,
                    'clear': <method 'clear' of 'xml.etree.ElementTree.Element' objects>,
                    'extend': <method 'extend' of 'xml.etree.ElementTree.Element' objects>,
                    'find': <method 'find' of 'xml.etree.ElementTree.Element' objects>,
                    'findall': <method 'findall' of 'xml.etree.ElementTree.Element' objects>,
                    'findtext': <method 'findtext' of 'xml.etree.ElementTree.Element' objects>,
                    'get': <method 'get' of 'xml.etree.ElementTree.Element' objects>,
                    'getchildren': <method 'getchildren' of 'xml.etree.ElementTree.Element' objects>,
                    'getiterator': <method 'getiterator' of 'xml.etree.ElementTree.Element' objects>,
                    'insert': <method 'insert' of 'xml.etree.ElementTree.Element' objects>,
                    'items': <method 'items' of 'xml.etree.ElementTree.Element' objects>,
                    'iter': <method 'iter' of 'xml.etree.ElementTree.Element' objects>,
                    'iterfind': <method 'iterfind' of 'xml.etree.ElementTree.Element' objects>,
                    'itertext': <method 'itertext' of 'xml.etree.ElementTree.Element' objects>,
                    'keys': <method 'keys' of 'xml.etree.ElementTree.Element' objects>,
                    'makeelement': <method 'makeelement' of 'xml.etree.ElementTree.Element' objects>,
                    'remove': <method 'remove' of 'xml.etree.ElementTree.Element' objects>,
                    'set': <method 'set' of 'xml.etree.ElementTree.Element' objects>,
                    'tag': <attribute 'tag' of 'xml.etree.ElementTree.Element' objects>,
                    'tail': <attribute 'tail' of 'xml.etree.ElementTree.Element' objects>,
                    'text': <attribute 'text' of 'xml.etree.ElementTree.Element' objects>})
      

      所以tag 不是实例变量,它是类变量,这就是为什么它出现在类的__dict__ 中,而不是出现在e__dict__ 中。

      其实ET.Element(e)的实例没有任何实例变量,只有ET.Element中定义的类变量。


      我不确定为什么库类没有__dict__ 而用户定义的类有,但我认为它与this answer 有关:

      [...] 这些通常是本机编码的(即用 C 编写的)——并且 __dict__ 属性必须被显式创建——因此与用 Python 编码的类不同——必须不遗余力地允许 __dict__ 进入这些类,而对于 Python 代码,绕道是避免 __dict__。

      【讨论】:

      • "其实ET.Element(e)的实例没有任何实例变量,只有ET.Element中定义的类变量。这是不正确的。您在类上看到的是 slots,它编码了如何直接访问实例内存中的属性。这些类似于property,它存在于类中,但指示对实例变量的访问。
      猜你喜欢
      • 2012-05-20
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2013-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多