python - 필터 - 파이썬 파일에서 문자열 찾기



Schrödinger의 변수:__class__ 셀이 존재하는지 확인하려면 마술처럼 나타납니다. (2)

이것은 Python 3의 인수없는 super 구현에서 이상한 상호 작용입니다. 메소드에서 super 에 액세스하면 메소드를 정의하는 클래스를 참조하는 숨겨진 __class__ 클로저 변수가 추가로 트리거됩니다. 구문 분석기는 메서드의 심볼 테이블에 __class__ 을 추가하여 메서드에서 이름 super 의 특수 사례를로드 한 다음 나머지 코드는 모두 super 대신 __class__ 를 찾습니다. 그러나 __class__ 직접 액세스하려고하면 __class__ 찾는 모든 코드 __class__ 코드를보고 super 처리를 수행해야한다고 생각합니다!

다음은 super 가 보이는 경우 심볼 테이블에 __class__ 라는 이름을 추가하는 위치입니다 .

case Name_kind:
    if (!symtable_add_def(st, e->v.Name.id,
                          e->v.Name.ctx == Load ? USE : DEF_LOCAL))
        VISIT_QUIT(st, 0);
    /* Special-case super: it counts as a use of __class__ */
    if (e->v.Name.ctx == Load &&
        st->st_cur->ste_type == FunctionBlock &&
        !PyUnicode_CompareWithASCIIString(e->v.Name.id, "super")) {
        if (!GET_IDENTIFIER(__class__) ||
            !symtable_add_def(st, __class__, USE))
            VISIT_QUIT(st, 0);
    }
    break;

다음은 drop_class_free 를 설정하는 ste_needs_class_closure .

static int
drop_class_free(PySTEntryObject *ste, PyObject *free)
{
    int res;
    if (!GET_IDENTIFIER(__class__))
        return 0;
    res = PySet_Discard(free, __class__);
    if (res < 0)
        return 0;
    if (res)
        ste->ste_needs_class_closure = 1;
    return 1;
}

ste_needs_class_closure 를 검사하고 암시 적 셀을 만드는 컴파일러 섹션 입니다.

if (u->u_ste->ste_needs_class_closure) {
    /* Cook up an implicit __class__ cell. */
    _Py_IDENTIFIER(__class__);
    PyObject *tuple, *name, *zero;
    int res;
    assert(u->u_scope_type == COMPILER_SCOPE_CLASS);
    assert(PyDict_Size(u->u_cellvars) == 0);
    name = _PyUnicode_FromId(&PyId___class__);
    if (!name) {
        compiler_unit_free(u);
        return 0;
    }
    ...

더 관련성 높은 코드가 있지만 모든 코드를 포함하는 것은 너무 어렵습니다. Python/compile.cPython/symtable.c 는 더 많이보고 싶다면 보게됩니다.

__class__ 라는 변수를 사용하려고하면 이상한 버그가 생길 수 있습니다 :

class Foo:
    def f(self):
        __class__ = 3
        super()

Foo().f()

산출:

Traceback (most recent call last):
  File "./prog.py", line 6, in <module>
  File "./prog.py", line 4, in f
RuntimeError: super(): __class__ cell not found

__class__ 대한 할당은 __class__ 이 클로저 변수 대신 로컬 변수이므로 클로저 셀 super() 필요가 없다는 것을 의미합니다.

def f():
    __class__ = 2
    class Foo:
        def f(self):
            print(__class__)

    Foo().f()

f()

산출:

<class '__main__.f.<locals>.Foo'>

둘러싸는 범위에 실제 __class__ 변수가 있어도 __class__ 의 특수 대소 문자는 변수를 둘러싸는 범위의 변수 값 대신 클래스를 얻는다는 것을 의미합니다.

https://code.i-harness.com

놀랍습니다.

>>> class B:
...     print(locals())
...     def foo(self):
...         print(locals())
...         print(__class__ in locals().values())
...         
{'__module__': '__main__', '__qualname__': 'B'}
>>> B().foo()
{'__class__': <class '__main__.B'>, 'self': <__main__.B object at 0x7fffe916b4a8>}
True

__class__ 대한 단순한 언급이 파서가 명시 적으로 확인한 것처럼 보입니다. 그렇지 않으면 우리는

NameError: name '__class__' is not defined

실제로 키 대신 만 확인하도록 수정하면 (즉, '__class__' in locals() 확인하는 경우 예상대로 범위 내에 있음).

이 변수가 마술처럼 범위 안으로 주입되는 것은 어떻게됩니까? 내 추측이 super 와 관련이있다.하지만 super 사용하지 않았기 때문에 컴파일러가 암시 적 클로저 참조를 만들지 않는 이유는 무엇인가?


https://docs.python.org/3/reference/datamodel.html#creating-the-class-object

__class__ 는 클래스 본문의 메서드 중 __class__ 또는 super를 참조하는 경우 컴파일러에서 만든 암시 적 클로저 참조입니다. 이것은 렉시 컬 스코핑을 기반으로 정의 된 클래스를 올바르게 식별 할 수 있도록 제로 인수 형태의 super() 를 허용하는 반면 현재 호출을하는 데 사용 된 클래스 또는 인스턴스는 메소드에 전달 된 첫 번째 인수를 기반으로 식별됩니다.





python-datamodel