Search code examples
pythonargumentsparameter-passingelementtreekeyword-argument

Why one can't pass 'parent' and 'tag' arguments as kwargs to SubElement factory function of xml.etree.ElementTree?


I'm using Python 3.6.5. What works:

from xml.etree.ElementTree import Element, SubElement
root = Element("root")
SubElement(root, "sub")

what doesn't:

from xml.etree.ElementTree import Element, SubElement
root = Element("root")
SubElement(parent=root, tag="sub")

So the only difference is passing parent and tag as keyword arguments (with proper keywords, mind you). Also look at the stack trace:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: SubElement() takes at least 2 arguments (0 given)

How on Earth there were 0 arguments given?

A look at the source for SubElement: lines 443:459 hasn't struck me with any revelations. As you can see the two positional parameters of SubElement are indeed named parent and tag.

Are we to have second thoughts about validity of this particular Raymond Hettinger's piece of advice?


Solution

  • The reason of that behavior can be found at the end of ElementTree.py:

    # 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
        from _elementtree import *
    except ImportError:
        pass
    

    The Python code you can read (def SubElement(parent, tag, attrib={}, **extra)) is NOT the one that will be used when you call SubElement() from your own code. Instead, a more efficient version, written in C and compiled for your OS, will be used. This ensure better performances of the library.

    As a result, some syntaxic sugar usually available in Python (ability to choose between named arguments or positional ones) may not be available.