如何获取子类中未继承自父类的专属属性(常规方法无效)
Got it, let's tackle this problem. You want to extract all attributes that a subclass defines on its own—excluding anything inherited from the parent class—and you noted that the straightforward approach of taking the difference between parent and subclass attribute sets isn't suitable here. Let's break down reliable solutions for both class-level and instance-level attributes:
1. 获取子类独有的类属性
Subclasses store their own defined class attributes in their __dict__ attribute; inherited class attributes won't appear here unless the subclass explicitly overrides them. We just need to filter out Python's built-in special attributes (those starting and ending with double underscores):
class Parent: parent_class_attr = "Inherited class attribute" def __init__(self): self.parent_instance_attr = 42 class Child(Parent): child_class_attr = "Child's own class attribute" parent_class_attr = "Overridden parent attribute" # This counts as Child's own def __init__(self): super().__init__() self.child_instance_attr = 100 # Extract unique class attributes of Child child_unique_class_attrs = [key for key in Child.__dict__.keys() if not key.startswith('__') and not key.endswith('__')] print(child_unique_class_attrs) # Output: ['child_class_attr', 'parent_class_attr']
This approach correctly includes overridden parent attributes since they're redefined in the subclass, and excludes any inherited attributes that weren't touched.
2. 获取子类独有的实例属性
Instance attributes defined in the parent's __init__ will show up in the subclass instance's __dict__, so we need a way to isolate attributes that are explicitly set in the subclass's initialization logic. We can use Python's inspect and ast modules to parse the subclass's __init__ method:
import inspect import ast def extract_instance_attrs_from_init(cls): # Get the source code of the subclass's __init__ method init_source = inspect.getsource(cls.__init__) # Parse the code into an Abstract Syntax Tree (AST) tree = ast.parse(init_source) instance_attrs = [] # Traverse the AST to find self.xxx assignments for node in ast.walk(tree): if isinstance(node, ast.Assign): for target in node.targets: if (isinstance(target, ast.Attribute) and isinstance(target.value, ast.Name) and target.value.id == 'self'): instance_attrs.append(target.attr) return instance_attrs # Extract instance attributes defined in Child child_instance_attrs = extract_instance_attrs_from_init(Child) print(child_instance_attrs) # Output: ['child_instance_attr']
This method directly pulls out instance attributes that the subclass sets on its own, ignoring anything inherited from the parent's initialization.
3. 合并结果:获取所有子类自定义属性
If you want a combined list of both class and instance attributes, just wrap the above methods together:
def get_all_child_unique_attrs(child_cls): # Get unique class attributes class_attrs = [key for key in child_cls.__dict__.keys() if not key.startswith('__') and not key.endswith('__')] # Get unique instance attributes instance_attrs = extract_instance_attrs_from_init(child_cls) return { "class_attributes": class_attrs, "instance_attributes": instance_attrs } # Get full result for Child class result = get_all_child_unique_attrs(Child) print(result) # Output: # { # "class_attributes": ["child_class_attr", "parent_class_attr"], # "instance_attributes": ["child_instance_attr"] # }
Why does the naive set difference approach fail? Using set(dir(Child)) - set(dir(Parent)) would return a bunch of built-in special attributes (like __weakref__) that are inherited from object, not defined by the subclass. It also doesn't properly distinguish between overridden attributes and truly inherited ones. The methods above avoid these issues by targeting exactly what the subclass defines explicitly.
内容的提问来源于stack exchange,提问作者Awaish Kumar

