Dies ist eine seltsame Interaktion in Python 3-Implementierung von No-Argument super
. Ein Zugriff auf super
in einer Methode löst das Hinzufügen einer versteckten __class__
Abschlussvariable aus, die sich auf die Klasse bezieht, die die Methode definiert. Der Parser sperrt eine Methode mit dem Namen super
in einer Methode, indem er auch __class__
der Symboltabelle der Methode hinzufügt, und dann sucht der Rest des relevanten Codes nach __class__
statt super
. Wenn Sie jedoch versuchen, auf __class__
selbst zuzugreifen, sieht der gesamte Code, der nach __class__
sucht, es und denkt, dass es die super
Behandlung tun sollte!
Here's where it adds the name __class__
to the symbol table if it sees super
:
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;
Hier drop_class_free
, das setzt 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;
}
Die compiler section die ste_needs_class_closure
und schafft die implizite Zelle überprüft:
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;
}
...
Es gibt mehr re levant-Code, aber es ist zu viel, um alles mit einzubeziehen. Python/compile.c
und Python/symtable.c
sind wo Sie suchen, wenn Sie mehr sehen möchten.
Sie können einige seltsame Fehler erhalten, wenn Sie versuchen, eine Variable __class__
Namen zu verwenden:
class Foo:
def f(self):
__class__ = 3
super()
Foo().f()
Ausgang:
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
Die Zuordnung zu __class__
bedeutet __class__
ist eine lokale Variable anstelle eines Verschlusses Variable, so dass die Schließzelle super()
braucht nicht da ist.
def f():
__class__ = 2
class Foo:
def f(self):
print(__class__)
Foo().f()
f()
Ausgang:
<class '__main__.f.<locals>.Foo'>
Obwohl gibt es ein tatsächlichen __class__
Variable in dem umschließenden Umfang, das für eine spezielles Gehäuse __class__
bedeutet, dass Sie die Klasse erhalten anstelle der Anwendungsbereichs des Variablenwert umschließt.
Dies ist * dokumentiert *? Nun, jetzt fühle ich mich dumm, die Quelle dafür zu durchforsten. Das ist eine bessere Antwort als meine. – user2357112
Keine der beiden Antworten erklärt mir wirklich, warum die Referenz erstellt werden muss, wenn Super nicht verwendet wurde. – wim
@wim: Es muss nicht erstellt werden. Es ist einfach so. Ich nehme an, dass die Implementierung einfach so funktioniert und dann haben sie es dokumentiert, weil es nicht groß genug war, um sich zu ändern, anstatt dass es sich um ein Design handelt. – user2357112