2016-01-02 11 views
5

Recentemente ho passato il codice sorgente CPython, visualizzando in particolare lo symbol table entry per una classe durante la compilazione.Chiusure su __class__

mi sono imbattuto nella seguente voce per la struttura typedef struct _symtable_entry:

[-- other entries --] 
unsigned ste_needs_class_closure : 1; /* for class scopes, true if a 
             closure over __class__ 
             should be created */ 
[-- other entries --] 

Io davvero non riesco a capire e non riesco a trovare un esempio di codice Python che in realtà imposta ste_needs_class_closure == 1. Tra gli altri tentativi falliti, ho provato quanto segue:

class foo: 
    y = 30 
    def __init__(self): 
     self.x = 50 
    def foobar(self): 
     def barfoo(): 
      print(self.x) 
      print(y) 
     return barfoo 

Ma anche se si esegue, il valore di ste_needs_class_closure durante l'esecuzione è 0 e non 1 come speravo che sarebbe stato.

La funzione che modifica effettivamente questo valore è drop_class_free che non aiuta molto. Sfortunatamente, non ha commenti che lo completino.

in realtà è utilizzato in analyze_block con un commento di:

/* Check if any local variables must be converted to cell variables */ 

che posso comprendere come concetto, ma non riesce a trovare un esempio in cui accade.

Ho provato a cercare the changelog for Python 3.4, la versione in cui questo membro è apparso per la prima volta ma non sono stati trovati riferimenti ad esso.

Quindi qualcuno può spiegare cosa si intende per chiusura su __class__ ovvero quando le variabili locali di una classe vengono convertite in variabili di cella? Idealmente, un esempio che rende questo comportamento visibile durante l'esecuzione sarebbe meraviglioso.

risposta

2

Github’s blame view for that line of code ci mostra che è stata aggiunta nel this commit, che fa riferimento Issue #12370: Impedire corpi di classe di interferire con la chiusura __class__.

Dalla segnalazione di bug, un esempio del tipo di problema questo stava cercando di risolvere il problema è:

In Python 3 Il codice seguente stampa False perché l'uso di super() ha causato il descrittore __class__ di essere omesso dallo spazio dei nomi della classe . Rimuovere l'uso di super e stampa True.

class X(object): 
    def __init__(self): 
     super().__init__() 

    @property 
    def __class__(self): 
     return int 

print (isinstance(X(), int)) 

(Si noti che questo codice utilizza il new super().)

Per quanto riguarda la funzionalità della patch, anche dal bug report:

La patch provoca sostanzialmente la seguente dichiarazione di classe:

class C(A, B, metaclass=meta): 
    def f(self): 
     return __class__ 

essere compilato circa così:

def _outer_C(*__args__, **__kw__): 
    class _inner_C(*__args__, **__kw__): 
     def f(self): 
      return __class__ 
    __class__ = _inner_C 
    return _inner_C 
C = _outer_C(A, B, metaclass=meta) 

... anche se qualche discussione successiva suggerisce che la manipolazione di __args__ e __kw__ potrebbe essere cambiata nella patch finale.