[Python-de] Nicht-Hashbare Elemente schnell zugreifen

Andreas Pakulat apaku at gmx.de
Mon Jun 26 14:25:42 CEST 2006


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.