Python中super()与__closure__的关联解析及相关技术疑问解答
Great questions! Let's break these down one by one, using Python's internal mechanics as our guide:
1. Why does Derived.b have a __closure__ but Derived.d doesn't?
The key difference boils down to the parameterless super() call in b().
When you use super() without arguments inside a method, Python needs to know two critical things at runtime:
- The class where the method is defined (to calculate the Method Resolution Order, MRO)
- The instance the method is invoked on
During the compilation of the Derived class, the compiler spots this parameterless super() and realizes it needs to "hold onto" the Derived class reference for later. Since the class isn't fully initialized when the method is being compiled, Python stores this reference in a closure cell—hence the non-empty __closure__ attribute on Derived.b.
In contrast, d() doesn't use super() or reference any variables from the enclosing class scope that aren't already accessible via standard method arguments or globals. There's no need to capture external state, so __closure__ remains None.
2. What does Derived.b.__closure__[0].cell_contents == __main__.Derived mean?
That cell contains the class object where the method was defined—in this case, the Derived class itself.
When super() runs without parameters, it uses this captured class to navigate the MRO: it skips Derived and picks the next implementation of b() (which is Base.b here). The closure cell is just a way to preserve this class reference between the method's compilation and its execution.
3. Can we use cell_contents to detect if a method called super()?
Sort of—but it's not a foolproof solution, with important caveats:
- Works for parameterless
super(): If a method usessuper()without arguments, it will almost always have a closure cell pointing to its defining class. Checking for this cell can be a reliable heuristic for this specific case. - Fails for explicit-parameter
super(): If someone writessuper(Base, self).b()instead, the compiler doesn't need to capture the enclosing class (since it's explicitly provided).__closure__will beNoneeven thoughsuper()is called. - False positives exist: A method could have a non-empty
__closure__for unrelated reasons—like referencing a non-local variable from the class scope (e.g., a class-level constant defined before the method).
As a rough heuristic, you could use something like this (with the above caveats in mind):
def uses_parameterless_super(method): if not method.__closure__: return False # Check if any closure cell holds the method's defining class class_name = method.__qualname__.split('.')[0] for cell in method.__closure__: if getattr(cell.cell_contents, '__name__', '') == class_name: return True return False
内容的提问来源于stack exchange,提问作者aikiOr

