gpt4 book ai didi

python - 在 Python 中调用每个祖先的方法

转载 作者:行者123 更新时间:2023-11-28 21:30:38 25 4
gpt4 key购买 nike

我在 python 中有一个类“D”的对象,我想顺序执行“D”及其每个祖先(“A”、“B”和“C”)定义的“run”方法.

我能够像这样完成这个

class A(object):
def run_all(self):
# I prefer to execute in revere MRO order
for cls in reversed(self.__class__.__mro__):
if hasattr(cls, 'run'):
# This works
cls.run(self)
# This doesn't
#cls.__getattribute__(self, 'run')()

def run(self):
print "Running A"

class B(A):
def run(self):
print "Running B"

class C(A):
def run(self):
print "Running C"

class D(C, B):
def run(self):
print "Running D"

if __name__ == "__main__":
D().run_all()

结果

$ python test.py 
Running A
Running B
Running C
Running D

但是在实践中我不知道要执行的方法的名称。但是如果我使用 getattribute() (请参阅注释)行尝试此操作,它将不起作用:

$ python test.py 
Running D
Running D
Running D
Running D

所以我的问题是:

  1. 为什么不起作用?

  2. 这是解决这个问题的最佳方法吗?

最佳答案

如果您同意更改所有 run 实现(并在 D 中调用 run 而不是 run_all),则以下方法有效:

class A(object):
def run(self):
print "Running A"

class B(A):
def run(self):
super(B, self).run()
print "Running B"

class C(A):
def run(self):
super(C, self).run()
print "Running C"

class D(C, B):
def run(self):
super(D, self).run()
print "Running D"

if __name__ == "__main__":
D().run()

请注意,我没有在根类中使用super——它“知道”没有进一步的父类(super class)可以向上(object code> 未定义 run 方法)。不幸的是,在 Python 2 中,这不可避免地很冗长(并且也不太适合通过装饰器实现)。

你对hasattr的检查非常脆弱,如果我正确理解你的目的的话——它会发现一个类“拥有”该属性,如果它定义或继承它。因此,如果您有一个不重写 run 但确实出现在 __mro__ 上的中间类,则它继承的 run 版本会被调用两次在你的方法中。例如,考虑:

class A(object):
def run_all(self):
for cls in reversed(self.__class__.__mro__):
if hasattr(cls, 'run'):
getattr(cls, 'run')(self)
def run(self):
print "Running A"
class B(A): pass
class C(A):
def run(self):
print "Running C"
class D(C, B): pass

if __name__ == "__main__":
D().run_all()

这个打印

Running A
Running A
Running C
Running C

对于 BD 继承而不覆盖的 run 版本有两个“口吃”(来自 AC)。假设我是对的,这不是您想要的效果,如果您热衷于避免 super 您可以尝试将 run_all 更改为:

def run_all(self):
for cls in reversed(self.__class__.__mro__):
meth = cls.__dict__.get('run')
if meth is not None: meth(self)

将其替换为我的最新示例,在 AC 中仅用两个不同的 def 来表示 run ,使示例打印:

Running A
Running C

我怀疑这可能更接近你想要的。

还有一点:不要重复这项工作 - hasattr 保护 getattr,或者 in 测试保护 dict 访问 - 保护中的检查和 protected 访问器都必须重复在内部进行完全相同的工作,没有什么好处。相反,对单个 getattr 调用(或字典的 get 方法)使用第三个参数 None :这意味着如果该方法如果不存在,您将检索 None 值,然后您可以防止调用发生这种情况。这正是 dicts 有 get 方法和 getattr 有第三个可选“默认”参数的原因:为了轻松应用 DRY,“不要重复自己” ,良好编程的一个非常重要的格言!-)

关于python - 在 Python 中调用每个祖先的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1989863/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com