2015-05-14 27 views
5

Ich ging durch den Code für six.py in the django utils, die für Nicht-Jython-Implementierungen versucht, die MAXSIZE für den Int zu finden. Nun, die Art und Weise, wie dies gemacht wird, ist interessant - anstatt eine Ausnahme für die Anweisung selbst zu erfassen, wird die Anweisung in eine __len__ Methode in einer benutzerdefinierten Klasse eingeschlossen. Was kann der Grund dafür sein?Warum verwendet six.py eine benutzerdefinierte Klasse zum Suchen von MAXSIZE?

class X(object): 
    def __len__(self): 
     return 1 << 31 
try: 
    len(X()) 
except OverflowError: 
    # 32-bit 
    MAXSIZE = int((1 << 31) - 1) 
else: 
    # 64-bit 
    MAXSIZE = int((1 << 63) - 1) 
del X 

Wenn ich nicht falsch liege, könnte dies auch für die unten als auch verkürzt wurde, nicht wahr?

try: 
    1 << 31 
except OverflowError: 
    # 32-bit 
    MAXSIZE = int((1 << 31) - 1) 
else: 
    # 64-bit 
    MAXSIZE = int((1 << 63) - 1) 

Antwort

4

int in python3 ist eine Poly-Glot Art von Klasse, die Maschine ints sowie big-ints darstellen kann; ein Feature, das die Unterscheidung zwischen int und long in python2 überflüssig macht. Auf python3 gibt die Konstruktion int(1 << n) niemals einen Fehler aus.

Also, um das zu lösen, sechs verwendet einen ordentlichen Trick, Kräfte Python, um etwas in eine Maschine Größe int stopfen. Der len builtin Trys immer den Rückgabewert von __len__ in eine Maschine große Sache zu konvertieren:

>>> class Lengthy(object): 
...  def __init__(self, x): 
...   self.x = x 
...  def __len__(self): 
...   return self.x 
...  
>>> int(1<<100) 
1267650600228229401496703205376L 
>>> type(int(1<<100)) 
<type 'long'> 
>>> len(Lengthy(1<<100)) 
Traceback (most recent call last): 
    File "<ipython-input-6-6b1b77348950>", line 1, in <module> 
    len(Lengthy(1<<100)) 
OverflowError: long int too large to convert to int 

>>> 

oder in Python 3, die Ausnahme ist etwas anders:

>>> len(Lengthy(1<<100)) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
OverflowError: cannot fit 'int' into an index-sized integer 
>>> 
+0

Dies scheint sie zu beantworten. Haben Sie einen Link für das 'Die eingebaute Lenin versucht immer, den Rückgabewert von __len__ in eine maschinengroße Sache umzuwandeln '..? –

+1

Das relevanteste Bit, 'PyObject_Size' ist so definiert, dass es ein' Py_ssize_t' zurückgibt (siehe https://hg.python.org/cpython/file/b4cbecbc0781/Objects/abstract.c#l43), was letztendlich die Funktion ist, die wird (über ein paar Makro-Direktionen) von dem eingebauten "len" aufgerufen. – SingleNegationElimination