2016-11-29 1 views
1

Ich versuche, zu testen und beheben a bug in pprint++ (edit: the correct link; original link left for posterity), die nach oben kommen, weil der instancemethod Typ nicht hashable ist:Wo finde ich eine Instanzmethode in der Python 3-Standardbibliothek?

In [16]: import pandas as pd 

In [17]: type(pd.tslib.NaT).__repr__ 
Out[17]: <instancemethod __repr__ at 0x1058d2be8> 

In [18]: hash(type(pd.tslib.NaT).__repr__) 
    ... 
TypeError: unhashable type: 'instancemethod' 

Aber ich habe Probleme für dieses Problem testen habe, weil ich don‘ Ich weiß, wo ich sonst noch einen instancemethod in der Python 3-Standardbibliothek finden kann, und ich möchte nicht, dass meine Tests von Pandas abhängen.

Insbesondere scheint es, wie die „normale“ eingebaute Typen haben „Instanzmethoden“, die etwas anders umgesetzt werden:

In [19]: type(None).__repr__ 
Out[19]: <slot wrapper '__repr__' of 'NoneType' objects> 

In [20]: hash(type(None).__repr__) 
Out[20]: -9223372036583849574 

Also: Wo kann ich ein instancemethod in der Python-3-Standard-Bibliothek zu finden, so kann ich Versuche dagegen schreiben? Oder ist es ein spezieller Typ, der dort nicht erscheint?

(Anmerkung: dies scheint nur 2 Python 3, als die gleiche Methode in Python zu beeinflussen ist ein unbound method, die hashable ist)

+1

Wenn Hilfe, 'instancemethod' in 'C' umgesetzt wird in' classobject.c' siehe [hier] (https://github.com/python /cpython/blob/c30098c8c6014f3340a369a31df9c74bdbacc269/Objects/classobject.c#L608). –

+0

Ich bin nicht sicher, ob der Link das ist, was Sie veröffentlichen wollten. –

+0

Das sieht richtig aus. Wenn Sie den Code jedoch schnell durchlesen, werden keine Instanzen angezeigt, in denen er in der Codebasis cpython3 verwendet wird. Möglicherweise ist es nicht, und es wird nur von Erweiterungen verwendet? –

Antwort

3

Diese Art nicht in irgendetwas verwendet wird, die mit Python kommt, und es gibt keine API auf Python-Ebene zum Erstellen von Objekten dieses Typs. Sie können jedoch mit einem direkten C-API-Aufruf tun:

import ctypes 

PyInstanceMethod_New = ctypes.pythonapi.PyInstanceMethod_New 
PyInstanceMethod_New.argtypes = (ctypes.py_object,) 
PyInstanceMethod_New.restype = ctypes.py_object 

arbitrary_callable = sum 

instance_method = PyInstanceMethod_New(arbitrary_callable) 

Der Name instancemethod sehen viel wie ein gebundenes Methodenobjekt, aber es stellt sich heraus, dass es etwas ganz anderes ist. Es ist eine seltsame interne Sache, die laut ihrer die neue Möglichkeit für C-Typen sein soll, ihre Methoden zu repräsentieren, außer dass die Standard-C-Level-API zum Erstellen eines Typs sie nicht tatsächlich verwendet.

Nach conversations auf dem Python Issue Tracker wurde diese Funktion von den Entwicklern von Cython und Pyrex angefordert. Es sieht so aus, als wäre pandas.tslib.NaT in Cython implementiert, und die Cython-Implementierung verwendet diesen Typ, wo die Standard-C-API zum Erstellen von Typen dies nicht tut. Beachten Sie, dass die Situation in Python 2 völlig anders ist. In Python 2 war dieser neue Typ nicht vorhanden, und instancemethod war der Name des Typs von Methodenobjekten, die gewöhnliche in Python geschriebene Methoden darstellten. In Python 3 hat der neue Typ diesen Namen angenommen, und der Typ der Methodenobjekte für in Python geschriebene Methoden heißt jetzt method.

+0

Dang, das ist super! Vielen Dank! –

2

Python bietet es, aber grundsätzlich nur als Teil ihrer Testsuite AFAICT (keine mitgelieferten Akkus verwenden es sonst). Sie können mit dem _testcapi Modul eine für die Prüfung machen:

>>> import _testcapi 
>>> testinstancemethod = _testcapi.instancemethod(str.__repr__) 
>>> hash(testinstancemethod) 
... 
TypeError: unhashable type: 'instancemethod' 
+0

Sie haben mich leicht geschlagen [entdecken] (https://github.com/python/cpython/blob/4265fa04206b29b3ec653d74a620b0413306023f/Lib/test/test_capi.py#L36) und posting this :-D –

+0

Ich glaube, Sie haben etwas in '_testcapi fallengelassen (str .__ repr __) '. – user2357112

+0

@ user2357112: Ups. Das ist, was ich bekomme, wenn ich nicht direkt kopieren und einfügen möchte. Fest. :-) – ShadowRanger