Ada*_*kin 68 python inheritance dynamic
本文有一个片段__bases__,通过向类继承的类的现有类集合添加一个类来动态更改某些Python代码的继承层次结构.好的,这很难读,代码可能更清晰:
class Friendly:
def hello(self):
print 'Hello'
class Person: pass
p = Person()
Person.__bases__ = (Friendly,)
p.hello() # prints "Hello"
Run Code Online (Sandbox Code Playgroud)
也就是说,Person不从Friendly源级别继承,而是通过修改__bases__Person类的属性在运行时动态添加此继承关系.但是,如果您更改Friendly并Person成为新的样式类(通过继承自object),则会收到以下错误:
TypeError: __bases__ assignment: 'Friendly' deallocator differs from 'object'
Run Code Online (Sandbox Code Playgroud)
关于这一点的谷歌搜索似乎表明,在运行时更改继承层次结构时,新样式类和旧样式类之间存在一些不兼容性.具体来说:"新式类对象不支持赋予其基础属性".
我的问题是,是否有可能通过使用__mro__属性使上述Friendly/Person示例在Python 2.7+中使用新式类工作?
免责声明:我完全意识到这是一个模糊的代码.我完全意识到,在实际的生产代码中,这样的技巧往往难以理解,这纯粹是一个思想实验,并且可以让人们了解Python如何处理与多重继承相关的问题.
Ada*_*kin 34
好的,再次,这不是您通常应该做的事情,这仅供参考.
Python在实例对象上查找方法的位置取决于__mro__定义该对象的类的属性(M ethod R esolution O rder属性).因此,如果我们可以修改__mro__of Person,我们就会得到理想的行为.就像是:
setattr(Person, '__mro__', (Person, Friendly, object))
Run Code Online (Sandbox Code Playgroud)
问题是这__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!
Run Code Online (Sandbox Code Playgroud)
这不做的是修改任何以前创建的Person实例以获得该hello()方法.例如(只是修改main()):
def main():
oldperson = Person()
ModifyPersonToBeFriendly()
p = Person()
p.hello()
# works! But:
oldperson.hello()
# does not
Run Code Online (Sandbox Code Playgroud)
如果电话的细节type不清楚,那么请阅读e-satisf'关于'什么是Python中的元类?'的优秀答案..
Mit*_*del 21
我也一直在努力解决这个问题,并且对你的解决方案很感兴趣,但Python 3将它从我们手中夺走:
AttributeError: attribute '__dict__' of 'type' objects is not writable
Run Code Online (Sandbox Code Playgroud)
我实际上需要一个装饰器来替换装饰类的(单个)超类.这里需要包含太长的描述(我尝试过,但是无法将其设置为合理的长度和有限的复杂性 - 它出现在基于Python的企业服务器的许多Python应用程序的使用环境中不同的应用程序需要稍微不同的代码变体.)
对此页面和其他类似讨论提供的提示暗示,分配的问题__bases__仅发生在没有定义超类的类(即,其唯一的超类是对象).通过将我需要替换的超类定义为一个普通类的子类,我能够解决这个问题(适用于Python 2.7和3.2):
## T is used so that the other classes are not direct subclasses of object,
## since classes whose base is object don't allow assignment to their __bases__ attribute.
class T: pass
class A(T):
def __init__(self):
print('Creating instance of {}'.format(self.__class__.__name__))
## ordinary inheritance
class B(A): pass
## dynamically specified inheritance
class C(T): pass
A() # -> Creating instance of A
B() # -> Creating instance of B
C.__bases__ = (A,)
C() # -> Creating instance of C
## attempt at dynamically specified inheritance starting with a direct subclass
## of object doesn't work
class D: pass
D.__bases__ = (A,)
D()
## Result is:
## TypeError: __bases__ assignment: 'A' deallocator differs from 'object'
Run Code Online (Sandbox Code Playgroud)
我不能保证后果,但是这个代码在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 them
class newFriendly: pass
newFriendly.__dict__ = dict(Friendly.__dict__)
Friendly = newFriendly
class newPerson: pass
newPerson.__dict__ = dict(Person.__dict__)
Person = newPerson
p = Person()
Person.__bases__ = (Friendly,)
p.hello() # prints "Hello"
Run Code Online (Sandbox Code Playgroud)
我们知道这是可能的.凉.但我们永远不会使用它!
| 归档时间: |
|
| 查看次数: |
31611 次 |
| 最近记录: |