2015-05-14 17 views
5

Stavo passando attraverso il codice per six.py in the django utils, che, per implementazioni non Jython, cerca, per trovare il MAXSIZE per l'int. Ora, il modo in cui questo viene fatto è interessante - invece di rilevare un'eccezione nell'istruzione stessa, l'istruzione è racchiusa all'interno di un metodo __len__ in una classe personalizzata. Quale può essere la ragione per farlo?Perché six.py usa la classe personalizzata per trovare 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 

Se non sbaglio, lo stesso avrebbe potuto essere abbreviato anche in basso, giusto?

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

risposta

4

int in python3 è un poli-glot sorta di classe che può rappresentare interi macchina nonché big int; una funzionalità che supera la distinzione tra int e long in python2. Su python3, la costruzione int(1 << n) non genera mai un errore.

Quindi per risolvere questo, sei sta usando un trucco ordinario che forza python per racchiudere qualcosa in una macchina di dimensioni int. Il len incorporato trys sempre per convertire il valore di ritorno di __len__ in una cosa di dimensioni macchina:

>>> 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 

>>> 

o, in Python 3, l'eccezione è leggermente diverso:

>>> 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

Questo sembra rispondere. Avete un link per il 'Len builtin trys sempre per convertire il valore di ritorno di __len__ in una cosa di dimensioni macchina '..? –

+1

Il bit più pertinente, 'PyObject_Size' è definito per restituire un' Py_ssize_t' (vedere https://hg.python.org/cpython/file/b4cbecbc0781/Objects/abstract.c#l43), che in definitiva è la funzione che viene chiamato (tramite alcune macro indirette) dal file 'len' incorporato. – SingleNegationElimination