Closing over __class__

I recently switched to the CPython source code, especially looking at the compilation of the symbol table entry for the class.

I came across the following entry for the typedef struct _symtable_entry structure 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 --] 

I really can't figure it out and can't find a python code example that actually sets ste_needs_class_closure == 1 . Among other unsuccessful attempts, I tried the following:

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

But even if it executes, the value of ste_needs_class_closure at runtime is 0 , not 1 , as I hoped it would be.

The function that actually changes this value is drop_class_free , which helps a little. Unfortunately, he also has no comments to supplement him.

It is actually used in analyze_block with a comment:

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

What I can understand as a concept, but I can not find an example where this happens.

I tried to find the change log for Python 3.4 , the version in which this member first appeared, but no links to it were found.

So, can anyone explain what is meant by closure over __class __ , that is, when local class variables are converted to cell variables? Ideally, the example that actually makes this behavior visible at runtime would be great.

+5
source share
1 answer

The Githubs widget for this line of code shows us that it has been added to this commit , which refers to Problem No. 12370 : Prevent Interferences to __class__ .

From the error report, an example of the type of problem he was trying to fix:

In Python 3, the following code prints False , since using super() made the __class__ descriptor __class__ omitted from the namespace. Remove the use of super and print True .

 class X(object): def __init__(self): super().__init__() @property def __class__(self): return int print (isinstance(X(), int)) 

(Note that this code uses the new super () .)

Regarding the functionality of the patch, also from the bug report:

The patch basically calls the following class statement:

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

Compile something like this:

 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) 

... although in a later discussion it is assumed that the processing of __args__ and __kw__ can be changed in the last patch.

+2
source

Source: https://habr.com/ru/post/1239650/


All Articles