Maxim
Maxim

Reputation: 1803

Can't set attributes on ElementTree.Element instance in Python 3

I don't understand why in Python 3 I can't add some attributes to ElementTree.Element instances. Here is the difference:

In Python 2:

Python 2.6.6 (r266:84292, Jun 18 2012, 14:18:47) 
[GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from xml.etree import ElementTree as ET
>>> el = ET.Element('table')
>>> el.foo = 50
>>> el.foo
50
>>> 

In Python 3:

Python 3.3.0 (default, Sep 11 2013, 16:29:08) 
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from xml.etree import ElementTree as ET
>>> el = ET.Element('table')
>>> el.foo = 50
>>> el.foo
AttributeError: foo
>>> 

Python 2 is provided by a distribution (CentOS). Python 3 was compiled from sources.

Is it intended behavior, a bug, or do I have to recompile python 3 with some additional flags?

UPDATE:

Some clarification: I am trying to set attributes on Python object, i.e. on Element instance. Not XML attributes (Element.attrib).

This issue actually arose when I tried to subclass Element. Here is example:

>>> class Table(ET.Element):
...     def __init__(self):
...         super().__init__('table')
...         print('calling __init__')
...         self.foo = 50
... 
>>> t = Table()
calling __init__
>>> t.foo
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'Table' object has no attribute 'foo'
>>> 

This makes me think that Element class is instantiated in some tricky way, but I can't figure out what goes on. Hence the question.

Upvotes: 5

Views: 2051

Answers (3)

RandomName
RandomName

Reputation: 11

Since 3.3 ElementTree tries to import the c implementation in for efficiency, however you can't set arbitrary attributes on that implementation. If you are in a situation where you don't want to use the Set or Get methods every time, you should use ET._Element_Py, which is the Python implementation.

Upvotes: 1

Corley Brigman
Corley Brigman

Reputation: 12411

It's probably intentional... take a look at Can't set attributes of object class . If they haven't enhanced ElementTree to use slots instead of dict in that time, i would be surprised anyways.

Not clear what you are trying to do... are you really trying to set python attributes, or XML attributes? If the latter, you really want to do this:

el = ET.Element('table')
el.set('foo', 50) 
#or
el.attrib['foo'] = 50

If you really want to add python attributes, you should subclass instead, and probably provide your own Element/SubElement functions to supply the 'wrapped' elements instead of standard ones.

Update 6/4/2016: Maybe not clear from my answer, but here's what you probably need to do (I'm normally python 2.7):

class Table(ET.Element):
    # Adding __slots__ gives it a known attribute to use    
    __slots__ = ('foo',)
    def __init__(self):
        super().__init__('table')
        print('calling __init__')
        self.foo = 50

Upvotes: 1

filaton
filaton

Reputation: 2326

According to Python 3 documentation, it seems that the only way to go is now:

>>> from xml.etree import ElementTree as ET
>>> el = ET.Element('table')
>>> el.set("foo", 50)
>>> el.get("foo")
50
>>> el.attrib
{"foo": 50}

It worked under Python 2.X too but is probably mandatory now.

Also, an interesting ticket in Python bug tracker where they decided to change the exception message.

Upvotes: 0

Related Questions