Visitar URL original
gh-87729: add LOAD_SUPER_ATTR instruction for faster super() by carljm · Pull Request #103497 · python/cpython · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
move __class__ special case out of the fast path
  • Loading branch information
carljm committed Apr 20, 2023
commit df442c0deb2f3dec8bfbd01fd97a5e00080b4096
17 changes: 17 additions & 0 deletions Lib/test/test_super.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,23 @@ def method(self):
with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
Comment thread
carljm marked this conversation as resolved.
C().method()

def test_super___class__(self):
class C:
def method(self):
return super().__class__

self.assertEqual(C().method(), super)

def test_super_subclass___class__(self):
class mysuper(super):
pass

class C:
def method(self):
return mysuper(C, self).__class__

self.assertEqual(C().method(), mysuper)


if __name__ == "__main__":
unittest.main()
15 changes: 8 additions & 7 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -9370,13 +9370,6 @@ do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
if (su_obj_type == NULL)
goto skip;

/* We want __class__ to return the class of the super object
(i.e. super, or a subclass), not the class of su->obj. */
if (PyUnicode_Check(name) &&
PyUnicode_GET_LENGTH(name) == 9 &&
_PyUnicode_Equal(name, &_Py_ID(__class__)))
goto skip;

mro = su_obj_type->tp_mro;
if (mro == NULL)
goto skip;
Expand Down Expand Up @@ -9452,6 +9445,14 @@ static PyObject *
super_getattro(PyObject *self, PyObject *name)
{
superobject *su = (superobject *)self;

/* We want __class__ to return the class of the super object
(i.e. super, or a subclass), not the class of su->obj. */
if (PyUnicode_Check(name) &&
PyUnicode_GET_LENGTH(name) == 9 &&
_PyUnicode_Equal(name, &_Py_ID(__class__)))
return PyObject_GenericGetAttr(self, name);

return do_super_lookup(su, su->type, su->obj, su->obj_type, name, NULL);
}

Expand Down
10 changes: 6 additions & 4 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -4237,18 +4237,20 @@ is_import_originated(struct compiler *c, expr_ty e)
}

static int
can_optimize_super_call(struct compiler *c, expr_ty e)
can_optimize_super_call(struct compiler *c, expr_ty attr)
{
expr_ty e = attr->v.Attribute.value;
if (e->kind != Call_kind ||
e->v.Call.func->kind != Name_kind ||
!_PyUnicode_EqualToASCIIString(e->v.Call.func->v.Name.id, "super") ||
_PyUnicode_EqualToASCIIString(attr->v.Attribute.attr, "__class__") ||
asdl_seq_LEN(e->v.Call.keywords) != 0) {
return 0;
}
Py_ssize_t num_args = asdl_seq_LEN(e->v.Call.args);

PyObject *super_name = e->v.Call.func->v.Name.id;
// try to detect statically-visible shadowing of 'super' name
// detect statically-visible shadowing of 'super' name
int scope = _PyST_GetScope(c->u->u_ste, super_name);
if (scope != GLOBAL_IMPLICIT) {
return 0;
Expand Down Expand Up @@ -4388,7 +4390,7 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
/* Alright, we can optimize the code. */
location loc = LOC(meth);

if (can_optimize_super_call(c, meth->v.Attribute.value)) {
if (can_optimize_super_call(c, meth)) {
RETURN_IF_ERROR(load_args_for_super(c, meth->v.Attribute.value));
int opcode = asdl_seq_LEN(meth->v.Attribute.value->v.Call.args) ?
LOAD_SUPER_METHOD : LOAD_ZERO_SUPER_METHOD;
Expand Down Expand Up @@ -5406,7 +5408,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
return compiler_formatted_value(c, e);
/* The following exprs can be assignment targets. */
case Attribute_kind:
if (e->v.Attribute.ctx == Load && can_optimize_super_call(c, e->v.Attribute.value)) {
if (e->v.Attribute.ctx == Load && can_optimize_super_call(c, e)) {
RETURN_IF_ERROR(load_args_for_super(c, e->v.Attribute.value));
int opcode = asdl_seq_LEN(e->v.Attribute.value->v.Call.args) ?
LOAD_SUPER_ATTR : LOAD_ZERO_SUPER_ATTR;
Expand Down