__repr__装饰器在子类中失效的原因及修复方法咨询
Container class decorated with __repr__dec trigger a TypeError? Let's break down the issue and fix it step by step.
The Root Cause
Chances are your __repr__dec decorator has a critical flaw in how it defines the replacement __repr__ method: it doesn't include the required self parameter for instance methods.
When you decorate a class with your decorator, it replaces the class's __repr__ with a function that doesn't accept an instance argument. Then, when you create a subclass and try to call __repr__ on its instance, Python automatically passes the instance as the first argument to the method—but your decorated __repr__ can't handle that, hence the TypeError (you'll usually see a message like "new_repr() takes 0 positional arguments but 1 was given").
Another less common scenario is if your decorator replaces the original class entirely (e.g., returns a new subclass of the original) without properly preserving metadata or handling metaclasses, but the missing self parameter is far more likely.
How to Fix It
We need to adjust the decorator to generate a valid instance method, and also make it subclass-friendly. Here's a corrected implementation:
import functools def __repr__dec(cls): # Optional: Preserve the original __repr__ in case we need it later original_repr = cls.__repr__ @functools.wraps(original_repr) def new_repr(self): # Collect all instance attributes, using !r to get proper repr formatting for values attr_str = ", ".join(f"{key}={value!r}" for key, value in self.__dict__.items()) # Use self.__class__.__name__ to ensure subclasses show their own class name return f"{self.__class__.__name__}({attr_str})" # Replace the class's __repr__ with our improved version cls.__repr__ = new_repr return cls
Key Improvements:
- Added
selfparameter: Thenew_reprfunction now accepts the instance argument, making it a valid instance method. - Subclass-friendly naming: Using
self.__class__.__name__instead of hardcoding the parent class name means subclasses will display their own class name in the repr output, not justContainer. - Preserved metadata:
functools.wrapscopies over metadata from the original__repr__(like docstrings and method names), which avoids subtle compatibility issues. - Better value formatting: Using
value!rensures each attribute's value uses its own__repr__for consistent, Pythonic output.
Test It Out
With this corrected decorator, inheritance works as expected:
@__repr__dec class Container: def __init__(self, x): self.x = x class SubContainer(Container): def __init__(self, x, y): super().__init__(x) self.y = y # Test parent class c = Container(42) print(c) # Output: Container(x=42) # Test subclass sc = SubContainer(10, "hello world") print(sc) # Output: SubContainer(x=10, y='hello world')
No more TypeError, and the repr output works correctly for both parent and child classes.
内容的提问来源于stack exchange,提问作者James Draper

