猿问

如何在运行时动态更改实例的基类?

本文的摘要显示了__bases__通过将类添加到继承它的现有类的类集合中来动态更改某些Python代码的继承层次结构的用法。好的,这很难看懂,代码可能更清晰:


class Friendly:

    def hello(self):

        print 'Hello'


class Person: pass


p = Person()

Person.__bases__ = (Friendly,)

p.hello()  # prints "Hello"

也就是说,Person它不是从Friendly源级别继承的,而是通过修改__bases__Person类的属性在运行时动态添加此继承关系。但是,如果更改Friendly并Person成为新的样式类(通过从object继承),则会出现以下错误:


TypeError: __bases__ assignment: 'Friendly' deallocator differs from 'object'

对此进行一些谷歌搜索似乎表明新样式类和旧样式类在运行时更改继承层次结构方面存在一些不兼容性。具体来说:“新型类对象不支持对其bases属性的分配”。


我的问题是,是否可以使用Python 2.7+中的新型类,使上面的Friendly / Person示例工作,可能是通过使用__mro__属性?


免责声明:我完全意识到这是晦涩的代码。我完全意识到,在实际的生产代码中,这样的技巧往往难以理解,这纯粹是一个思想实验,并且让人们从中学习有关Python如何处理与多重继承相关的问题的知识。


慕斯王
浏览 557回答 3
3回答

至尊宝的传说

好的,再次,这不是您通常应该执行的操作,仅用于提供信息。其中的Python查找一个实例对象的方法是由确定__mro__它定义了对象(该类的属性中号 ethod ř esolution ö刻申属性)。因此,如果我们能够改变__mro__的Person,我们会得到期望的行为。就像是:setattr(Person, '__mro__', (Person, Friendly, object))问题是这__mro__是一个只读属性,因此setattr将不起作用。也许如果您是Python专家,那么可以采取一些措施,但显然我没有达到专家地位,因为我想不到。一个可能的解决方法是简单地重新定义该类:def modify_Person_to_be_friendly():    # so that we're modifying the global identifier 'Person'    global Person    # now just redefine the class using type(), specifying that the new    # class should inherit from Friendly and have all attributes from    # our old Person class    Person = type('Person', (Friendly,), dict(Person.__dict__)) def main():    modify_Person_to_be_friendly()    p = Person()    p.hello()  # works!这不做的是修改任何先前创建的Person实例以使用该hello()方法。例如(仅修改main()):def main():    oldperson = Person()    ModifyPersonToBeFriendly()    p = Person()    p.hello()      # works!  But:    oldperson.hello()    # does not如果type调用的细节不清楚,请阅读e-satis关于“ Python中的元类是什么?”的出色答案。。

GCT1015

我不能保证后果,但是这段代码可以满足您在py2.7.2上的要求。class Friendly(object):    def hello(self):        print 'Hello'class Person(object): pass# we can't change the original classes, so we replace themclass newFriendly: passnewFriendly.__dict__ = dict(Friendly.__dict__)Friendly = newFriendlyclass newPerson: passnewPerson.__dict__ = dict(Person.__dict__)Person = newPersonp = Person()Person.__bases__ = (Friendly,)p.hello()  # prints "Hello"我们知道这是可能的。凉。但是我们永远不会使用它!
随时随地看视频慕课网APP

相关分类

Python
我要回答