Commit 14aa280d authored by Martin v. Löwis's avatar Martin v. Löwis

Use __slots__ throughout instead of __dict__, to reduce the memory usage.

parent 32ac92cd
...@@ -283,27 +283,23 @@ class ExpatBuilder: ...@@ -283,27 +283,23 @@ class ExpatBuilder:
elif childNodes and childNodes[-1].nodeType == TEXT_NODE: elif childNodes and childNodes[-1].nodeType == TEXT_NODE:
node = childNodes[-1] node = childNodes[-1]
value = node.data + data value = node.data + data
d = node.__dict__ node.data = value
d['data'] = d['nodeValue'] = value
return return
else: else:
node = minidom.Text() node = minidom.Text()
d = node.__dict__ node.data = data
d['data'] = d['nodeValue'] = data node.ownerDocument = self.document
d['ownerDocument'] = self.document
_append_child(self.curNode, node) _append_child(self.curNode, node)
def character_data_handler(self, data): def character_data_handler(self, data):
childNodes = self.curNode.childNodes childNodes = self.curNode.childNodes
if childNodes and childNodes[-1].nodeType == TEXT_NODE: if childNodes and childNodes[-1].nodeType == TEXT_NODE:
node = childNodes[-1] node = childNodes[-1]
d = node.__dict__ node.data = node.data + data
d['data'] = d['nodeValue'] = node.data + data
return return
node = minidom.Text() node = minidom.Text()
d = node.__dict__ node.data = node.data + data
d['data'] = d['nodeValue'] = node.data + data node.ownerDocument = self.document
d['ownerDocument'] = self.document
_append_child(self.curNode, node) _append_child(self.curNode, node)
def entity_decl_handler(self, entityName, is_parameter_entity, value, def entity_decl_handler(self, entityName, is_parameter_entity, value,
...@@ -363,11 +359,8 @@ class ExpatBuilder: ...@@ -363,11 +359,8 @@ class ExpatBuilder:
a = minidom.Attr(attributes[i], EMPTY_NAMESPACE, a = minidom.Attr(attributes[i], EMPTY_NAMESPACE,
None, EMPTY_PREFIX) None, EMPTY_PREFIX)
value = attributes[i+1] value = attributes[i+1]
d = a.childNodes[0].__dict__ a.value = value
d['data'] = d['nodeValue'] = value a.ownerDocument = self.document
d = a.__dict__
d['value'] = d['nodeValue'] = value
d['ownerDocument'] = self.document
_set_attribute_node(node, a) _set_attribute_node(node, a)
if node is not self.document.documentElement: if node is not self.document.documentElement:
...@@ -761,11 +754,8 @@ class Namespaces: ...@@ -761,11 +754,8 @@ class Namespaces:
else: else:
a = minidom.Attr("xmlns", XMLNS_NAMESPACE, a = minidom.Attr("xmlns", XMLNS_NAMESPACE,
"xmlns", EMPTY_PREFIX) "xmlns", EMPTY_PREFIX)
d = a.childNodes[0].__dict__ a.value = uri
d['data'] = d['nodeValue'] = uri a.ownerDocuemnt = self.document
d = a.__dict__
d['value'] = d['nodeValue'] = uri
d['ownerDocument'] = self.document
_set_attribute_node(node, a) _set_attribute_node(node, a)
del self._ns_ordered_prefixes[:] del self._ns_ordered_prefixes[:]
...@@ -785,12 +775,9 @@ class Namespaces: ...@@ -785,12 +775,9 @@ class Namespaces:
aname, EMPTY_PREFIX) aname, EMPTY_PREFIX)
_attrs[aname] = a _attrs[aname] = a
_attrsNS[(EMPTY_NAMESPACE, aname)] = a _attrsNS[(EMPTY_NAMESPACE, aname)] = a
d = a.childNodes[0].__dict__ a.ownerDocument = self.document
d['data'] = d['nodeValue'] = value a.value = value
d = a.__dict__ a.ownerElement = node
d['ownerDocument'] = self.document
d['value'] = d['nodeValue'] = value
d['ownerElement'] = node
if __debug__: if __debug__:
# This only adds some asserts to the original # This only adds some asserts to the original
......
...@@ -286,10 +286,10 @@ def _append_child(self, node): ...@@ -286,10 +286,10 @@ def _append_child(self, node):
childNodes = self.childNodes childNodes = self.childNodes
if childNodes: if childNodes:
last = childNodes[-1] last = childNodes[-1]
node.__dict__["previousSibling"] = last node.previousSibling = last
last.__dict__["nextSibling"] = node last.nextSibling = node
childNodes.append(node) childNodes.append(node)
node.__dict__["parentNode"] = self node.parentNode = self
def _in_document(node): def _in_document(node):
# return True iff node is part of a document tree # return True iff node is part of a document tree
...@@ -342,9 +342,10 @@ class DocumentFragment(Node): ...@@ -342,9 +342,10 @@ class DocumentFragment(Node):
class Attr(Node): class Attr(Node):
__slots__=('_name', '_value', 'namespaceURI',
'_prefix', 'childNodes', '_localName', 'ownerDocument', 'ownerElement')
nodeType = Node.ATTRIBUTE_NODE nodeType = Node.ATTRIBUTE_NODE
attributes = None attributes = None
ownerElement = None
specified = False specified = False
_is_id = False _is_id = False
...@@ -352,12 +353,11 @@ class Attr(Node): ...@@ -352,12 +353,11 @@ class Attr(Node):
def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None, def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
prefix=None): prefix=None):
# skip setattr for performance self.ownerElement = None
d = self.__dict__ self._name = qName
d["nodeName"] = d["name"] = qName self.namespaceURI = namespaceURI
d["namespaceURI"] = namespaceURI self._prefix = prefix
d["prefix"] = prefix self.childNodes = NodeList()
d['childNodes'] = NodeList()
# Add the single child node that represents the value of the attr # Add the single child node that represents the value of the attr
self.childNodes.append(Text()) self.childNodes.append(Text())
...@@ -365,8 +365,9 @@ class Attr(Node): ...@@ -365,8 +365,9 @@ class Attr(Node):
# nodeValue and value are set elsewhere # nodeValue and value are set elsewhere
def _get_localName(self): def _get_localName(self):
if 'localName' in self.__dict__: try:
return self.__dict__['localName'] return self._localName
except AttributeError:
return self.nodeName.split(":", 1)[-1] return self.nodeName.split(":", 1)[-1]
def _get_name(self): def _get_name(self):
...@@ -375,20 +376,30 @@ class Attr(Node): ...@@ -375,20 +376,30 @@ class Attr(Node):
def _get_specified(self): def _get_specified(self):
return self.specified return self.specified
def __setattr__(self, name, value): def _get_name(self):
d = self.__dict__ return self._name
if name in ("value", "nodeValue"):
d["value"] = d["nodeValue"] = value def _set_name(self, value):
d2 = self.childNodes[0].__dict__ self._name = value
d2["data"] = d2["nodeValue"] = value
if self.ownerElement is not None: if self.ownerElement is not None:
_clear_id_cache(self.ownerElement) _clear_id_cache(self.ownerElement)
elif name in ("name", "nodeName"):
d["name"] = d["nodeName"] = value nodeName = name = property(_get_name, _set_name)
def _get_value(self):
return self._value
def _set_value(self, value):
self._value = value
self.childNodes[0].data = value
if self.ownerElement is not None: if self.ownerElement is not None:
_clear_id_cache(self.ownerElement) _clear_id_cache(self.ownerElement)
else: self.childNodes[0].data = value
d[name] = value
nodeValue = value = property(_get_value, _set_value)
def _get_prefix(self):
return self._prefix
def _set_prefix(self, prefix): def _set_prefix(self, prefix):
nsuri = self.namespaceURI nsuri = self.namespaceURI
...@@ -396,22 +407,16 @@ class Attr(Node): ...@@ -396,22 +407,16 @@ class Attr(Node):
if nsuri and nsuri != XMLNS_NAMESPACE: if nsuri and nsuri != XMLNS_NAMESPACE:
raise xml.dom.NamespaceErr( raise xml.dom.NamespaceErr(
"illegal use of 'xmlns' prefix for the wrong namespace") "illegal use of 'xmlns' prefix for the wrong namespace")
d = self.__dict__ self._prefix = prefix
d['prefix'] = prefix
if prefix is None: if prefix is None:
newName = self.localName newName = self.localName
else: else:
newName = "%s:%s" % (prefix, self.localName) newName = "%s:%s" % (prefix, self.localName)
if self.ownerElement: if self.ownerElement:
_clear_id_cache(self.ownerElement) _clear_id_cache(self.ownerElement)
d['nodeName'] = d['name'] = newName self.name = newName
def _set_value(self, value): prefix = property(_get_prefix, _set_prefix)
d = self.__dict__
d['value'] = d['nodeValue'] = value
if self.ownerElement:
_clear_id_cache(self.ownerElement)
self.childNodes[0].data = value
def unlink(self): def unlink(self):
# This implementation does not call the base implementation # This implementation does not call the base implementation
...@@ -586,8 +591,8 @@ class NamedNodeMap(object): ...@@ -586,8 +591,8 @@ class NamedNodeMap(object):
_clear_id_cache(self._ownerElement) _clear_id_cache(self._ownerElement)
del self._attrs[n.nodeName] del self._attrs[n.nodeName]
del self._attrsNS[(n.namespaceURI, n.localName)] del self._attrsNS[(n.namespaceURI, n.localName)]
if 'ownerElement' in n.__dict__: if hasattr(n, 'ownerElement'):
n.__dict__['ownerElement'] = None n.ownerElement = None
return n return n
else: else:
raise xml.dom.NotFoundErr() raise xml.dom.NotFoundErr()
...@@ -598,8 +603,8 @@ class NamedNodeMap(object): ...@@ -598,8 +603,8 @@ class NamedNodeMap(object):
_clear_id_cache(self._ownerElement) _clear_id_cache(self._ownerElement)
del self._attrsNS[(n.namespaceURI, n.localName)] del self._attrsNS[(n.namespaceURI, n.localName)]
del self._attrs[n.nodeName] del self._attrs[n.nodeName]
if 'ownerElement' in n.__dict__: if hasattr(n, 'ownerElement'):
n.__dict__['ownerElement'] = None n.ownerElement = None
return n return n
else: else:
raise xml.dom.NotFoundErr() raise xml.dom.NotFoundErr()
...@@ -659,6 +664,9 @@ class TypeInfo(object): ...@@ -659,6 +664,9 @@ class TypeInfo(object):
_no_type = TypeInfo(None, None) _no_type = TypeInfo(None, None)
class Element(Node): class Element(Node):
__slots__=('ownerDocument', 'parentNode', 'tagName', 'nodeName', 'prefix',
'namespaceURI', '_localName', 'childNodes', '_attrs', '_attrsNS',
'nextSibling', 'previousSibling')
nodeType = Node.ELEMENT_NODE nodeType = Node.ELEMENT_NODE
nodeValue = None nodeValue = None
schemaType = _no_type schemaType = _no_type
...@@ -674,10 +682,12 @@ class Element(Node): ...@@ -674,10 +682,12 @@ class Element(Node):
def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None, def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
localName=None): localName=None):
self.parentNode = None
self.tagName = self.nodeName = tagName self.tagName = self.nodeName = tagName
self.prefix = prefix self.prefix = prefix
self.namespaceURI = namespaceURI self.namespaceURI = namespaceURI
self.childNodes = NodeList() self.childNodes = NodeList()
self.nextSibling = self.previousSibling = None
self._attrs = {} # attributes are double-indexed: self._attrs = {} # attributes are double-indexed:
self._attrsNS = {} # tagName -> Attribute self._attrsNS = {} # tagName -> Attribute
...@@ -688,8 +698,9 @@ class Element(Node): ...@@ -688,8 +698,9 @@ class Element(Node):
# namespaces. # namespaces.
def _get_localName(self): def _get_localName(self):
if 'localName' in self.__dict__: try:
return self.__dict__['localName'] return self._localName
except AttributeError:
return self.tagName.split(":", 1)[-1] return self.tagName.split(":", 1)[-1]
def _get_tagName(self): def _get_tagName(self):
...@@ -718,14 +729,11 @@ class Element(Node): ...@@ -718,14 +729,11 @@ class Element(Node):
attr = self.getAttributeNode(attname) attr = self.getAttributeNode(attname)
if attr is None: if attr is None:
attr = Attr(attname) attr = Attr(attname)
# for performance attr.value = value # also sets nodeValue
d = attr.__dict__ attr.ownerDocument = self.ownerDocument
d["value"] = d["nodeValue"] = value
d["ownerDocument"] = self.ownerDocument
self.setAttributeNode(attr) self.setAttributeNode(attr)
elif value != attr.value: elif value != attr.value:
d = attr.__dict__ attr.value = value
d["value"] = d["nodeValue"] = value
if attr.isId: if attr.isId:
_clear_id_cache(self) _clear_id_cache(self)
...@@ -733,23 +741,18 @@ class Element(Node): ...@@ -733,23 +741,18 @@ class Element(Node):
prefix, localname = _nssplit(qualifiedName) prefix, localname = _nssplit(qualifiedName)
attr = self.getAttributeNodeNS(namespaceURI, localname) attr = self.getAttributeNodeNS(namespaceURI, localname)
if attr is None: if attr is None:
# for performance
attr = Attr(qualifiedName, namespaceURI, localname, prefix) attr = Attr(qualifiedName, namespaceURI, localname, prefix)
d = attr.__dict__ attr.value = value
d["prefix"] = prefix attr.ownerDocument = self.ownerDocument
d["nodeName"] = qualifiedName
d["value"] = d["nodeValue"] = value
d["ownerDocument"] = self.ownerDocument
self.setAttributeNode(attr) self.setAttributeNode(attr)
else: else:
d = attr.__dict__
if value != attr.value: if value != attr.value:
d["value"] = d["nodeValue"] = value attr.value = value
if attr.isId: if attr.isId:
_clear_id_cache(self) _clear_id_cache(self)
if attr.prefix != prefix: if attr.prefix != prefix:
d["prefix"] = prefix attr.prefix = prefix
d["nodeName"] = qualifiedName attr.nodeName = qualifiedName
def getAttributeNode(self, attrname): def getAttributeNode(self, attrname):
return self._attrs.get(attrname) return self._attrs.get(attrname)
...@@ -874,7 +877,7 @@ class Element(Node): ...@@ -874,7 +877,7 @@ class Element(Node):
if _get_containing_entref(self) is not None: if _get_containing_entref(self) is not None:
raise xml.dom.NoModificationAllowedErr() raise xml.dom.NoModificationAllowedErr()
if not idAttr._is_id: if not idAttr._is_id:
idAttr.__dict__['_is_id'] = True idAttr._is_id = True
self._magic_id_nodes += 1 self._magic_id_nodes += 1
self.ownerDocument._magic_id_count += 1 self.ownerDocument._magic_id_count += 1
_clear_id_cache(self) _clear_id_cache(self)
...@@ -893,8 +896,7 @@ def _set_attribute_node(element, attr): ...@@ -893,8 +896,7 @@ def _set_attribute_node(element, attr):
# This creates a circular reference, but Element.unlink() # This creates a circular reference, but Element.unlink()
# breaks the cycle since the references to the attribute # breaks the cycle since the references to the attribute
# dictionaries are tossed. # dictionaries are tossed.
attr.__dict__['ownerElement'] = element attr.ownerElement = element
class Childless: class Childless:
"""Mixin that makes childless-ness easy to implement and avoids """Mixin that makes childless-ness easy to implement and avoids
...@@ -938,54 +940,49 @@ class Childless: ...@@ -938,54 +940,49 @@ class Childless:
class ProcessingInstruction(Childless, Node): class ProcessingInstruction(Childless, Node):
nodeType = Node.PROCESSING_INSTRUCTION_NODE nodeType = Node.PROCESSING_INSTRUCTION_NODE
__slots__ = ('target', 'data')
def __init__(self, target, data): def __init__(self, target, data):
self.target = self.nodeName = target self.target = target
self.data = self.nodeValue = data self.data = data
def _get_data(self): # nodeValue is an alias for data
def _get_nodeValue(self):
return self.data return self.data
def _set_data(self, value): def _set_nodeValue(self, value):
d = self.__dict__ self.data = data
d['data'] = d['nodeValue'] = value nodeValue = property(_get_nodeValue, _set_nodeValue)
def _get_target(self): # nodeName is an alias for target
def _get_nodeName(self):
return self.target return self.target
def _set_target(self, value): def _set_nodeName(self, value):
d = self.__dict__ self.target = value
d['target'] = d['nodeName'] = value nodeName = property(_get_nodeName, _set_nodeName)
def __setattr__(self, name, value):
if name == "data" or name == "nodeValue":
self.__dict__['data'] = self.__dict__['nodeValue'] = value
elif name == "target" or name == "nodeName":
self.__dict__['target'] = self.__dict__['nodeName'] = value
else:
self.__dict__[name] = value
def writexml(self, writer, indent="", addindent="", newl=""): def writexml(self, writer, indent="", addindent="", newl=""):
writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl)) writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
class CharacterData(Childless, Node): class CharacterData(Childless, Node):
__slots__=('_data', 'ownerDocument','parentNode', 'previousSibling', 'nextSibling')
def __init__(self):
self.ownerDocument = self.parentNode = None
self.previousSibling = self.nextSibling = None
self._data = ''
Node.__init__(self)
def _get_length(self): def _get_length(self):
return len(self.data) return len(self.data)
__len__ = _get_length __len__ = _get_length
def _get_data(self): def _get_data(self):
return self.__dict__['data'] return self._data
def _set_data(self, data): def _set_data(self, data):
d = self.__dict__ self._data = data
d['data'] = d['nodeValue'] = data
_get_nodeValue = _get_data
_set_nodeValue = _set_data
def __setattr__(self, name, value): data = nodeValue = property(_get_data, _set_data)
if name == "data" or name == "nodeValue":
self.__dict__['data'] = self.__dict__['nodeValue'] = value
else:
self.__dict__[name] = value
def __repr__(self): def __repr__(self):
data = self.data data = self.data
...@@ -1042,11 +1039,6 @@ defproperty(CharacterData, "length", doc="Length of the string data.") ...@@ -1042,11 +1039,6 @@ defproperty(CharacterData, "length", doc="Length of the string data.")
class Text(CharacterData): class Text(CharacterData):
# Make sure we don't add an instance __dict__ if we don't already
# have one, at least when that's possible:
# XXX this does not work, CharacterData is an old-style class
# __slots__ = ()
nodeType = Node.TEXT_NODE nodeType = Node.TEXT_NODE
nodeName = "#text" nodeName = "#text"
attributes = None attributes = None
...@@ -1112,9 +1104,7 @@ class Text(CharacterData): ...@@ -1112,9 +1104,7 @@ class Text(CharacterData):
else: else:
break break
if content: if content:
d = self.__dict__ self.data = content
d['data'] = content
d['nodeValue'] = content
return self return self
else: else:
return None return None
...@@ -1160,7 +1150,8 @@ class Comment(CharacterData): ...@@ -1160,7 +1150,8 @@ class Comment(CharacterData):
nodeName = "#comment" nodeName = "#comment"
def __init__(self, data): def __init__(self, data):
self.data = self.nodeValue = data CharacterData.__init__(self)
self._data = data
def writexml(self, writer, indent="", addindent="", newl=""): def writexml(self, writer, indent="", addindent="", newl=""):
if "--" in self.data: if "--" in self.data:
...@@ -1169,11 +1160,6 @@ class Comment(CharacterData): ...@@ -1169,11 +1160,6 @@ class Comment(CharacterData):
class CDATASection(Text): class CDATASection(Text):
# Make sure we don't add an instance __dict__ if we don't already
# have one, at least when that's possible:
# XXX this does not work, Text is an old-style class
# __slots__ = ()
nodeType = Node.CDATA_SECTION_NODE nodeType = Node.CDATA_SECTION_NODE
nodeName = "#cdata-section" nodeName = "#cdata-section"
...@@ -1504,18 +1490,19 @@ def _clear_id_cache(node): ...@@ -1504,18 +1490,19 @@ def _clear_id_cache(node):
node.ownerDocument._id_search_stack= None node.ownerDocument._id_search_stack= None
class Document(Node, DocumentLS): class Document(Node, DocumentLS):
__slots__ = ('_elem_info', 'doctype',
'_id_search_stack', 'childNodes', '_id_cache')
_child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE, _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE) Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
implementation = DOMImplementation()
nodeType = Node.DOCUMENT_NODE nodeType = Node.DOCUMENT_NODE
nodeName = "#document" nodeName = "#document"
nodeValue = None nodeValue = None
attributes = None attributes = None
doctype = None
parentNode = None parentNode = None
previousSibling = nextSibling = None previousSibling = nextSibling = None
implementation = DOMImplementation()
# Document attributes from Level 3 (WD 9 April 2002) # Document attributes from Level 3 (WD 9 April 2002)
...@@ -1530,6 +1517,7 @@ class Document(Node, DocumentLS): ...@@ -1530,6 +1517,7 @@ class Document(Node, DocumentLS):
_magic_id_count = 0 _magic_id_count = 0
def __init__(self): def __init__(self):
self.doctype = None
self.childNodes = NodeList() self.childNodes = NodeList()
# mapping of (namespaceURI, localName) -> ElementInfo # mapping of (namespaceURI, localName) -> ElementInfo
# and tagName -> ElementInfo # and tagName -> ElementInfo
...@@ -1815,17 +1803,15 @@ class Document(Node, DocumentLS): ...@@ -1815,17 +1803,15 @@ class Document(Node, DocumentLS):
element.removeAttributeNode(n) element.removeAttributeNode(n)
else: else:
element = None element = None
# avoid __setattr__ n.prefix = prefix
d = n.__dict__ n._localName = localName
d['prefix'] = prefix n.namespaceURI = namespaceURI
d['localName'] = localName n.nodeName = name
d['namespaceURI'] = namespaceURI
d['nodeName'] = name
if n.nodeType == Node.ELEMENT_NODE: if n.nodeType == Node.ELEMENT_NODE:
d['tagName'] = name n.tagName = name
else: else:
# attribute node # attribute node
d['name'] = name n.name = name
if element is not None: if element is not None:
element.setAttributeNode(n) element.setAttributeNode(n)
if is_id: if is_id:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment