python - 如何在 Python 中获取基类的属性?
问题描述
所以我正在编写一个允许人们编写命令集合的界面框架。
我在这里要做的是,对于 的每个子类Base
,找到它的所有具有描述的方法,然后收集所有这些函数并从中生成一个集体描述(加上其他东西,但它与这个问题无关)
这里是 MCVE
import types
class Meta(type):
def __init__(cls, *args, **kwargs):
cls._interfaces = {}
super().__init__(*args, **kwargs)
def __call__(cls, id, *args, **kwargs):
if id in cls._interfaces:
return cls._interfaces[id]
obj = cls.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
cls._interfaces[id] = obj
return obj
class Base(metaclass=Meta):
@property
def descriptions(self): # this doesn't work. It gives RecursionError
res=''
for name in dir(self):
attr=getattr(self,name)
if isinstance(attr, types.FunctionType) and hasattr(attr, 'description'):
res += f'{name}: {attr.description}\n'
return res
@property
def descriptions(self):
res=''
for cls in self.__class__.__mro__:
for name,attr in cls.__dict__.items():
if isinstance(attr, types.FunctionType) and hasattr(attr, 'description'):
res += f'{name}: {attr.description}\n'
return res
class A(Base):
def a(self): pass
a.description='A.a'
def b(self): pass
b.description='A.b'
class B(A):
def c(self): pass
c.description='B.c'
def d(self): pass
d.description='B.d'
print(B(0).descriptions)
现在我当前方法的问题是它没有检测到方法覆盖。假设我将此片段添加到类的定义中B
def a(self): pass
a.description='B.a'
现在生成的描述将完全错误。我想要的是,当一个方法被覆盖时,它收集的描述也被覆盖。因此,描述应该始终指向 Python 通常会解决的方法,如果人们以通常的方式(例如B.a.description
)
所以预期的输出将变为
a: B.a
b: A.b
c: B.c
d: B.d
我想我可以用单词制作一个特殊情况descriptions
并修复第description
一种方法。
但是有没有更优雅和 Pythonic 的方式来实现这一点?老实说,self.__class__.__mro__
看起来很可怕。
解决方案
当您迭代时self.__class__.__mro__
,您正在迭代解决顺序,这将<class '__main__.B'> <class '__main__.A'> <class '__main__.Base'> <class 'object'>
在您的示例中。
因此,您description
随后会查看这些类中的每一个的属性。当您a.description = 'B.a'
在类内部声明时B
,您实际上并没有在父类A
中覆盖它,您只是在子类中覆盖它B
。
所以,相反,你可以这样做:
import inspect
class Base(metaclass=Meta):
def descriptions(self):
res = ''
for mtd in inspect.getmembers(self, predicate=inspect.ismethod):
if hasattr(mtd[1], 'description'):
res += f'{mtd[0]}: {mtd[1].description}\n'
return res
这样,您只检查实际的孩子而不是其父母。但是,Base.descriptions
在这种情况下不能是属性,因为属性会在声明时进行评估,这会使inspect.getmembers
检查自身的时间无限长。
推荐阅读
- node.js - 当我将自定义域名添加到环境变量时,邮递员显示错误
- flutter - 如何使用 FlutterDriver 检查应用程序状态?
- javascript - 将 observable 转换为 jsx 组件
- c++ - 如果基类析构函数是虚拟的,则派生类的析构函数是否默认为虚拟?
- javascript - 如何在我的 Rmarkdown html 输出中获取复制按钮,以将 R 代码中生成的表格复制到剪贴板?
- c - 我在 C 二进制搜索代码中做错了什么?(迭代和递归)
- laravel - Laravel Eloquent 返回具有所有关系的模型
- jquery - Jquery加载并从加载和刷新中获取值
- azure-eventhub - 多个 EventGrid 订阅指向同一个端点
- html - 如何在页面布局中正确添加形状/装饰