Pythonic方式来了解属性是在哪个父节点中定义的

z5btuh9x  于 2023-06-28  发布在  Python
关注(0)|答案(2)|浏览(87)

如果我有这个类树:

@dataclass
class Parent():
  p: int = 42

@dataclass
class Child(Parent):
  c: int = 0

obj = Child()

从对象obj中,有没有一种简单的方法可以知道p是在Parent中定义的,而c是在Child中定义的?
我从顶部通过__mro__循环,获得那里的属性列表,并在层次结构中向下移动,获得尚未定义的新属性。它工作,但我想知道是否有一个更pythonic的方式。

编辑:上下文

它是关于自动生成的类,描述真实的世界的电力网络。
图像具有以下3个类,定义了一个树:

  • Equipment类定义name
  • ConductingEquipment定义resistance
  • Cable定义material

当然会有更多的设备类型和更多的传导设备类型。有一种标准的交换格式,它需要给出完全限定的属性名,所以即使对于Cable也是Equipment.name
所以在这个公认的奇怪的背景下,这是我确实需要做的事情。

kb5ga3dv

kb5ga3dv1#

像这样的吗

for attribute in vars(obj).keys():
    if attribute in vars(obj.__class__):
        print(f"Attribute '{attribute}' defined in {obj.__class__.__name__}")
    else:
        print(
            f"Attribute '{attribute}' inherited from {obj.__class__.__base__.__name__}"
        )

输出

Attribute 'p' inherited from Parent
Attribute 'c' defined in Child
q3qa4bjr

q3qa4bjr2#

在Python 3.10及更新版本中访问对象的注解字典
Python 3.10向标准库添加了一个新函数:inspect.get_annotations()。在Python 3.10及更新版本中,调用此函数是访问任何支持注解的对象的注解字典的最佳实践。这个函数还可以为你“取消字符串化”字符串化的注解。

If for some reason inspect.get_annotations() isn’t viable for your use case, you may access the __annotations__ data member manually.

最佳实践在Python 3.10中也发生了变化:从Python 3.10开始,o.annotations保证始终在Python函数、类和模块上工作。如果你确定你正在检查的对象是这三个特定对象中的一个,你可以简单地使用o.annotations来获取对象的annotations dict。
但是,其他类型的可调用对象(例如,由functools.partial()创建的可调用对象)可能没有定义annotations属性。当访问可能未知对象的annotations时,Python 3.10及更新版本中的最佳实践是使用三个参数调用getattr(),例如getattr(o,'annotations',None)。
在Python 3.10之前,访问一个类的annotations,如果这个类没有定义annotations,但是有一个带annotations的父类,则会返回父类的annotations。在Python 3.10及更新版本中,子类的注解将改为空dict。
在Python 3.9及更早的版本中,访问对象的注解字典要比新版本复杂得多。这个问题是这些较旧版本的Python中的一个设计缺陷,特别是与类注解有关。
访问其他对象(函数、其他可调用对象和模块)的注解dict的最佳实践与Python 3.10的最佳实践相同,假设您没有调用inspect.get_annotations():你应该使用三参数getattr()来访问对象的annotations属性。
不幸的是,这不是类的最佳实践。问题是,由于annotations在类上是可选的,并且由于类可以从其基类继承属性,因此访问类的annotations属性可能会无意中返回基类的annotations dict。

Python

@dataclass
class Parent():
    p: int = 42

@dataclass
class Child(Parent):
    c: int = 0

class Foo(Child):
    pass

parent = Parent()
child = Child()
foo = Foo()

输出3.7

print(f"Parent object annotations: {parent.__annotations__}")
print(f"Child object annotations: {child.__annotations__}")
print(f"Foo object annotations: {foo.__annotations__}")

Parent object annotations: {'p': <class 'int'>}
Child object annotations: {'c': <class 'int'>}
Foo object annotations: {'c': <class 'int'>} # <-- Wrong :(

python 3.10

print(f"Parent object annotations: {inspect.get_annotations(type(child))}")
print(f"Child object annotations: {inspect.get_annotations(type(parent))}")
print(f"Foo object annotations: {inspect.get_annotations(type(foo))}")

Parent object annotations: {'c': <class 'int'>}
Child object annotations: {'p': <class 'int'>}
Foo object annotations: {}

来源:https://docs.python.org/3/howto/annotations.html

相关问题