【问题标题】:__bases__ doesn't work! What's next?__bases__ 不起作用!下一步是什么?
【发布时间】:2010-07-07 08:36:35
【问题描述】:

以下代码在 Python 3.x 中不起作用,但它曾经适用于旧式类:

class Extender:
    def extension(self):
        print("Some work...")

class Base:
    pass

Base.__bases__ += (Extender,)

Base().extension()

问题很简单: 如何在 Python 3.x 中动态(在运行时)将超类添加到类中?

但我已经准备好答案将很难! )

【问题讨论】:

  • 你的基地不再属于你了?答案会很难吗?
  • 我认为这是不可能的,因为所有类都是 Python 3 中的新型类,如果 BaseobjectExtender 作为基类,则 MRO 将是模棱两可的.创建一个继承自 BaseExtender 的新类。 Extender 也可能是 ABC。

标签: python runtime python-3.x multiple-inheritance


【解决方案1】:

对我来说这是不可能的。但是您可以动态创建新类:

class Extender(object):
    def extension(self):
        print("Some work...")

class Base(object):
    pass

Base = type('Base', (Base, Extender, object), {})
Base().extension()

【讨论】:

  • 谢谢!您的解决方案效果很好! :) 但是我已经更新了一点 :$ 只添加一个新的基类就足够了:Base = type('Base', (Extender,), {}) 如果再次添加“Base”和“object”类,它们将在 MRO 中出现两次,解释器将寻找我认为属性很慢。
  • @DenisKolodin:MRO 中的两个 Base 是不同的类:新的和旧的。看看[id(cls) for cls in Base.__mro__] 看看它们是不同的。
  • 我已经对其进行了全面测试,并发现了一个严重的差异(((类型将仅针对新实例进行更改,但使用 bases)我可以更改现有实例中的属性,我需要。这个解决方案不一样!我还在搜索(
  • @DenisKolodin:也许尝试使用 copy.deepcopy
【解决方案2】:

看来可以动态更改Base.__bases__ 如果Base.__base__ 不是object。 (通过动态更改,我的意思是所有从Base 继承的预先存在的实例也会动态更改。否则请参阅Mykola Kharechko's solution)。

如果Base.__base__ 是某个虚拟类TopBase,那么分配给Base.__bases__ 似乎可行:

class Extender(object):
    def extension(self):
        print("Some work...")

class TopBase(object):
    pass

class Base(TopBase):
    pass

b=Base()
print(Base.__bases__)
# (<class '__main__.TopBase'>,)

Base.__bases__ += (Extender,)
print(Base.__bases__)
# (<class '__main__.TopBase'>, <class '__main__.Extender'>)
Base().extension()
# Some work...
b.extension()
# Some work...

Base.__bases__ = (Extender, TopBase) 
print(Base.__bases__)
# (<class '__main__.Extender'>, <class '__main__.TopBase'>)
Base().extension()
# Some work...
b.extension()
# Some work...

经过测试,它可以在 Python 2(用于新旧样式类)和 Python 3 中工作。我不知道为什么它可以工作,而这不能:

class Extender(object):
    def extension(self):
        print("Some work...")

class Base(object):
    pass

Base.__bases__ = (Extender, object)
# TypeError: __bases__ assignment: 'Extender' deallocator differs from 'object'

【讨论】:

  • 报错“cannot create a contrast..”的原因是因为你试图将Base.__base__的值(object,)改成(object, Extender),这是错误的根据 mro-order 到处走走。 (同样你不能说class X(object, Extender) 有类似的错误)。然而Base.__bases__ += (Extender,) + Base.__bases__ 只会抛出'E' deallocator differs from 'object',这完全是另一个错误,但仍然是一个错误。
  • 为了将来参考,有一个关于释放器错误的开放 CPython 问题:bugs.python.org/issue672115(自 2003 年开放,所以不要屏住呼吸)
猜你喜欢
  • 2013-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 2014-01-18
相关资源
最近更新 更多