S
Stefan Behnel
Steven D'Aprano, 27.05.2011 18:06:
I think Sturla is referring to the "compile time" bit. CPython cannot know
that the builtin super() will be called at runtime, even if it sees a
"super()" function call.
CPython doesn't evaluate the super call at compile time, it only keeps a
reference to the surrounding class in the code object of the method. So
super() without arguments basically inherits the class argument from the
context the method was found in at compile time. This has two quirks:
1) Copying a method from one class to another keeps the original context.
So the class argument to super() is basically fixed at compile time,
regardless of the class the method will be executed on at runtime.
2) The class is only kept as a reference when CPython sees a function call
that looks like "super" at compile time, which isn't much more than a
heuristic.
The PEP doesn't mention the first issue, but it is actually explicit about
the second issue:
http://www.python.org/dev/peps/pep-3135/
"""
While super is not a reserved word, the parser recognizes the use of super
in a method definition and only passes in the __class__ cell when this is
found. Thus, calling a global alias of super without arguments will not
necessarily work.
"""
And the prove:
... def test(self): print('TEST')
...... def meth(self): _super().test()
...Traceback (most recent call last):
SystemError: super(): __class__ cell not found
I assume this is done in order to reduce the chance of accidentally keeping
a class object alive for eternity, only because a method was originally
defined therein that inherits the class reference in its code object. So
it's a tradeoff between memory overhead and usability issues.
While I think that the tradeoff is generally ok, I agree with Sturla that a
keyword would have been the correct solution, whereas this is a clear
"works only in the common cases" approach.
Stefan
Why?
I think Sturla is referring to the "compile time" bit. CPython cannot know
that the builtin super() will be called at runtime, even if it sees a
"super()" function call.
CPython doesn't evaluate the super call at compile time, it only keeps a
reference to the surrounding class in the code object of the method. So
super() without arguments basically inherits the class argument from the
context the method was found in at compile time. This has two quirks:
1) Copying a method from one class to another keeps the original context.
So the class argument to super() is basically fixed at compile time,
regardless of the class the method will be executed on at runtime.
2) The class is only kept as a reference when CPython sees a function call
that looks like "super" at compile time, which isn't much more than a
heuristic.
The PEP doesn't mention the first issue, but it is actually explicit about
the second issue:
http://www.python.org/dev/peps/pep-3135/
"""
While super is not a reserved word, the parser recognizes the use of super
in a method definition and only passes in the __class__ cell when this is
found. Thus, calling a global alias of super without arguments will not
necessarily work.
"""
And the prove:
... def test(self): print('TEST')
...... def meth(self): _super().test()
...Traceback (most recent call last):
SystemError: super(): __class__ cell not found
I assume this is done in order to reduce the chance of accidentally keeping
a class object alive for eternity, only because a method was originally
defined therein that inherits the class reference in its code object. So
it's a tradeoff between memory overhead and usability issues.
While I think that the tradeoff is generally ok, I agree with Sturla that a
keyword would have been the correct solution, whereas this is a clear
"works only in the common cases" approach.
Stefan