Nicht-Hashbare Elemente schnell zugreifen
Hi, ich hab hier ein etwas verzwicktes Problem. Ich moechte in ein Dictionary mit nicht-hashbaren Objekte indizieren, prinzipiell zwar machbar mit id(), aber die Objekte sind aus einer C-Library (also gewrappte C-Objekte) und werden immer wieder neu erzeugt. Ich bekomme also fuer dasselbe Objekt aus der Library 2 verschiedene Python Objekte. Deswegen hatte ich nun schon einen Vergleichsoperator fuer diese Objekte geschrieben (auf C-Level kann man die Teile vergleichen). Hat jemand ne Idee wie ich das hinkriegen koennte ohne bei jeder Suche nach einem bestimmten Objekt einen Vergleich als Schleife zu schreiben? Konkret geht's um libxml2 und deren Python-Bindung (ich weiss es gibt lxml, ich will aber deren eigene Bindung), wenn man von einem xml-Knoten die Kinder besorgt sind das immer andere Python-Objekte, aber die zugrundeliegenden C-Objekte sind natuerlich gleich. Andreas -- Your supervisor is thinking about you. _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
Hi Andreas, Andreas Pakulat wrote:
ich hab hier ein etwas verzwicktes Problem. Ich moechte in ein Dictionary mit nicht-hashbaren Objekte indizieren, prinzipiell zwar machbar mit id(), aber die Objekte sind aus einer C-Library (also gewrappte C-Objekte) und werden immer wieder neu erzeugt. Ich bekomme also fuer dasselbe Objekt aus der Library 2 verschiedene Python Objekte. Deswegen hatte ich nun schon einen Vergleichsoperator fuer diese Objekte geschrieben (auf C-Level kann man die Teile vergleichen).
Spricht was dagegen, auch noch __hash__ zu implementieren? Hab das gerade mal für lxml gemacht, basierend auf der Adresse des C Objektes. Funktioniert wunderbar: cdef class Element: cdef xmlNode* _c_node def __hash__(self): return python.PyLong_FromVoidPtr(self._c_node) Solltest du den Autoren der libxml2 bindings vorschlagen. (Danke übrigens für die Idee). In lxml ist sowas weniger wichtig, da ohnehin während der Lebensdauer von Element Objekten immer das selbe Objekt zurückgeliefert wird. Solange sie also in einer Hash-Tabelle sind, wirst du auch immer das selbe Objekt (und damit den selben Hash-Key) von lxml bekommen. Nach dem, was du schreibst, scheint libxml2 diese Optimierung nicht zu haben. Stefan _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
Hallo,
ich hab hier ein etwas verzwicktes Problem. Ich moechte in ein Dictionary mit nicht-hashbaren Objekte indizieren, prinzipiell zwar machbar mit id(), aber die Objekte sind aus einer C-Library (also gewrappte C-Objekte) und werden immer wieder neu erzeugt. Ich bekomme also fuer dasselbe Objekt aus der Library 2 verschiedene Python Objekte. Deswegen hatte ich nun schon einen Vergleichsoperator fuer diese Objekte geschrieben (auf C-Level kann man die Teile vergleichen).
Spricht was dagegen, auch noch __hash__ zu implementieren? Hab das gerade mal für lxml gemacht, basierend auf der Adresse des C Objektes. Funktioniert wunderbar:
cdef class Element: cdef xmlNode* _c_node def __hash__(self): return python.PyLong_FromVoidPtr(self._c_node)
Solltest du den Autoren der libxml2 bindings vorschlagen. (Danke übrigens für die Idee). In lxml ist sowas weniger wichtig, da ohnehin während der Lebensdauer von Element Objekten immer das selbe Objekt zurückgeliefert wird. Solange sie also in einer Hash-Tabelle sind, wirst du auch immer das selbe Objekt (und damit den selben Hash-Key) von lxml bekommen. Nach dem, was du schreibst, scheint libxml2 diese Optimierung nicht zu haben.
Noch als addendum: anders gehts auch nicht - das einzige "auto-id"-Kriterium wäre der Pfad im XML-Dokument (also root/child[5]/subchild[3]). Und den errechnet man auch nicht in weniger als O(n) mit n = #(Elemente im Dokument) MfG Diez _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
On 26.06.06 13:11:02, Stefan Behnel wrote:
Andreas Pakulat wrote:
ich hab hier ein etwas verzwicktes Problem. Ich moechte in ein Dictionary mit nicht-hashbaren Objekte indizieren, prinzipiell zwar machbar mit id(), aber die Objekte sind aus einer C-Library (also gewrappte C-Objekte) und werden immer wieder neu erzeugt. Ich bekomme also fuer dasselbe Objekt aus der Library 2 verschiedene Python Objekte. Deswegen hatte ich nun schon einen Vergleichsoperator fuer diese Objekte geschrieben (auf C-Level kann man die Teile vergleichen).
Spricht was dagegen, auch noch __hash__ zu implementieren? Hab das gerade mal für lxml gemacht, basierend auf der Adresse des C Objektes. Funktioniert wunderbar:
cdef class Element: cdef xmlNode* _c_node def __hash__(self): return python.PyLong_FromVoidPtr(self._c_node)
Hmm, mal schauen, sollte nicht zu schwer sein, das mit dem Vergleich war ja auch viel einfacher als zuerst gedacht...
In lxml ist sowas weniger wichtig, da ohnehin während der Lebensdauer von Element Objekten immer das selbe Objekt zurückgeliefert wird. Solange sie also in einer Hash-Tabelle sind, wirst du auch immer das selbe Objekt (und damit den selben Hash-Key) von lxml bekommen. Nach dem, was du schreibst, scheint libxml2 diese Optimierung nicht zu haben.
Das Problem mit den libxml2 bindings ist IMHO dass sie jedesmal neue Python-Objekte generieren wenn man auf z.B. die children-Achse zugreift. Auch bei XPath Ausdruecken gibts immer neue Python-Objekte. Deswegen ja der == Operator, damit sowas wie nodes = EvaluateXPath() for node in nodes: if node in self.treenodes: highlight(self.treenodes[node]) funktioniert. Andreas -- Today's weirdness is tomorrow's reason why. -- Hunter S. Thompson _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
On 26.06.06 13:11:02, Stefan Behnel wrote:
Hi Andreas,
Andreas Pakulat wrote:
ich hab hier ein etwas verzwicktes Problem. Ich moechte in ein Dictionary mit nicht-hashbaren Objekte indizieren, prinzipiell zwar machbar mit id(), aber die Objekte sind aus einer C-Library (also gewrappte C-Objekte) und werden immer wieder neu erzeugt. Ich bekomme also fuer dasselbe Objekt aus der Library 2 verschiedene Python Objekte. Deswegen hatte ich nun schon einen Vergleichsoperator fuer diese Objekte geschrieben (auf C-Level kann man die Teile vergleichen).
Spricht was dagegen, auch noch __hash__ zu implementieren? Hab das gerade mal für lxml gemacht, basierend auf der Adresse des C Objektes. Funktioniert wunderbar:
cdef class Element: cdef xmlNode* _c_node def __hash__(self): return python.PyLong_FromVoidPtr(self._c_node)
Solltest du den Autoren der libxml2 bindings vorschlagen. (Danke übrigens für die Idee). In lxml ist sowas weniger wichtig, da ohnehin während der Lebensdauer von Element Objekten immer das selbe Objekt zurückgeliefert wird. Solange sie also in einer Hash-Tabelle sind, wirst du auch immer das selbe Objekt (und damit den selben Hash-Key) von lxml bekommen. Nach dem, was du schreibst, scheint libxml2 diese Optimierung nicht zu haben.
Hmm, funktioniert leider nicht so ganz. Fuer dasselbe Python Objekt liefert PyLong_FromVoidPtr(node) 2 verschiedene Werte bei aufeinanderfolgenden Aufrufen. Wobei node ein xmlNodePtr ist und das ganze im C-Layer passiert. Das ganze sieht so aus: ,---- libxml.c --- | static PyObject * | libxml_nodeHash(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { | | PyObject *py_node1; | xmlNodePtr node1; | | if (!PyArg_ParseTuple(args, (char *)"O:nodeHash", &py_node1)) | return NULL; | | node1 = PyxmlNode_Get(py_node1); | | return Py_BuildValue((char *)"l", PyLong_FromVoidPtr((void*)node1); | } `---- ,---- libxml.py ---- | class xmlCore: | def __hash__(self): | ret = libxml2mod.nodeHash(self._o) | return ret `---- Wobei PyxmlNode_Get den xmlNodePtr aus dem PyObject* "extrahiert". Was auch noch auffaellt: zwischen mehreren Python-Aufrufen des Skriptes ist der hash-Wert ebenso gleich... Jemand ne Idee? Andreas -- This will be a memorable month -- no matter how hard you try to forget it. _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
On 26.06.06 14:25:42, Andreas Pakulat wrote:
On 26.06.06 13:11:02, Stefan Behnel wrote:
cdef class Element: cdef xmlNode* _c_node def __hash__(self): return python.PyLong_FromVoidPtr(self._c_node)
Hmm, funktioniert leider nicht so ganz. Fuer dasselbe Python Objekt liefert PyLong_FromVoidPtr(node) 2 verschiedene Werte bei aufeinanderfolgenden Aufrufen. Wobei node ein xmlNodePtr ist und das ganze im C-Layer passiert.
Idee gut, Ausfuehrung mangelhaft...
Das ganze sieht so aus:
,---- libxml.c --- | static PyObject * | libxml_nodeHash(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { | | PyObject *py_node1; | xmlNodePtr node1; | | if (!PyArg_ParseTuple(args, (char *)"O:nodeHash", &py_node1)) | return NULL; | | node1 = PyxmlNode_Get(py_node1); | | return Py_BuildValue((char *)"l", PyLong_FromVoidPtr((void*)node1); | } `----
Hier darf ich natuerlich aus dem PyObject* nicht einen long machen lassen, sondern muss direkt das von PyLong_FromVoidPtr gelieferte PyObject* zurueckgeben. Naechster Wishlist-Bug fuer libxml2... Andreas -- You're a card which will have to be dealt with. _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
participants (3)
-
Andreas Pakulat
-
Diez B. Roggisch
-
Stefan Behnel