2016-01-02 14 views
5

Niedawno przechodziłem przez kod źródłowy CPython, szczególnie przeglądając symbol table entry dla klasy podczas kompilacji.Zamknięcia nad __class__

wpadłem na następujący wpis dotyczący struktury 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 --] 

ja naprawdę nie potrafię go zrozumieć i nie mogę znaleźć przykład kodu Pythona, który rzeczywiście ustala ste_needs_class_closure == 1. Wśród innych nieudanych prób, próbowałem następujące:

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

Ale mimo to wykonuje, wartość ste_needs_class_closure trakcie realizacji jest 0 i nie 1 jak miałem nadzieję, że będzie.

Funkcja, która faktycznie zmienia tę wartość, jest drop_class_free, co niewiele pomaga. Niestety, nie ma też żadnych komentarzy, które ją komplementują.

To jest faktycznie wykorzystywany w analyze_block z komentarzem:

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

Które mogę zrozumieć jako pojęcie, ale nie mogę znaleźć przykład, w którym to się dzieje.

Próbowałem wyszukać the changelog for Python 3.4, wersję, w której ten użytkownik pojawił się po raz pierwszy, ale nie znaleziono żadnych odniesień do niego.

Czy ktoś może wyjaśnić, co oznacza zamknięcie w stosunku do __class__, czyli kiedy zmienne lokalne klasy są konwertowane na zmienne komórki? Najlepiej byłoby, gdyby przykład, który rzeczywiście czyni to zachowanie widocznym podczas wykonywania, byłby cudowny.

Odpowiedz

2

Github’s blame view for that line of code pokazuje nam, że został dodany w this commit, która odwołuje Issue #12370: Zapobiegać ciał klasy zakłócaniu zamknięcia __class__.

Z raportu o błędzie, przykładem rodzaju problemu to starał się naprawić to:

W Pythonie 3 następujące drukuje kod False ponieważ korzystanie z super() spowodował deskryptor __class__ być pominięto w przestrzeni nazw klasy . Usuń użycie super i wydrukuje True.

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

    @property 
    def __class__(self): 
     return int 

print (isinstance(X(), int)) 

(Zauważ, że ten kod wykorzystuje new super().)

Odnośnie funkcjonalności plastra, również z raportu o błędzie:

Plaster zasadzie powoduje następujące oświadczenie Klasa:

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

być zestawiane w przybliżeniu tak:

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) 

... chociaż niektóre dyskusje sugerują później że obsługa __args__ i __kw__ mogła ulec zmianie w ostatecznej poprawce.