2010-07-07 5 views
7

Der folgende Code in Python 3.x funktioniert nicht, aber es verwendet, um mit alten Stil-Klassen zu arbeiten:__bases__ funktioniert nicht! Was kommt als nächstes?

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

class Base: 
    pass 

Base.__bases__ += (Extender,) 

Base().extension() 

Frage ist einfach:Wie kann ich hinzufügen, dynamisch (zur Laufzeit) Superklasse für eine Klasse in Python 3.x?

Aber ich bin bereit, die Antwort wird schwer sein!)

+9

Ihre Basen gehören Ihnen nicht mehr? Und die Antwort wird schwer? – Borealid

+0

Ich denke, das ist nicht mehr möglich, da alle Klassen neue Stilklassen in Python 3 sind, und die MRO wäre mehrdeutig, wenn "Base" sowohl "Objekt" als auch "Extender" als Basisklassen hätte. Erstellen Sie eine neue Klasse, die stattdessen von "Base" und "Extender" erbt. "Extender" könnte auch ein ABC sein. – Philipp

Antwort

4

Für mich ist es unmöglich. Aber Sie können dynamisch neue Klasse zu erstellen:

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

class Base(object): 
    pass 

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

Danke! Ihre Lösung funktioniert gut! :) Aber ich habe es ein bisschen aktualisiert: $ Es ist genug, nur eine neue Basisklasse hinzuzufügen: 'Base = type ('Basis', (Extender), {})' Wenn Sie 'Basis' und 'Objekt hinzufügen 'Klassen wieder erscheinen sie zweimal in der MRO und der Interpreter wird langsam nach Attributen suchen, denke ich. – DenisKolodin

+0

@DenisKolodin: Die beiden Basen in der MRO sind verschiedene Klassen: die neue und dann die alte. Betrachte '[id (cls) für cls in Base .__ mro __]' um zu sehen, dass sie unterschiedlich sind. – unutbu

+0

Ich habe es vollständig getestet und einen ernsten Unterschied gefunden (( Typ wird nur für neue Instanzen geändert, aber mit __bases__ Ich kann Attribute in vorhandenen Instanzen ändern, die ich brauche. Diese Lösung ist nicht ähnlich! Ich suche noch ( – DenisKolodin

3

Es scheint, dass es möglich ist, dynamisch Base.__bases__ zu ändern, wenn Base.__base__ nicht object. (Bei dynamischer Änderung meine ich, dass alle vorexistierenden Instanzen, die von Base erben, ebenfalls dynamisch geändert werden. Ansonsten siehe Mykola Kharechko's solution).

Wenn Base.__base__ einig Dummy-Klasse ist TopBase, dann Zuordnung zu Base.__bases__ scheint zu funktionieren:

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... 

Dies wurde getestet in Python 2 arbeiten (für Neu- und alten Stil-Klassen) und für Python 3. Ich habe keine Ahnung, warum es funktioniert, solange dies nicht funktioniert:

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' 
+0

Der Grund für den Fehler von "kann nicht eine konsistente erstellen." , das ist der falsche Weg nach mro-order. (Ebenso kann man nicht 'Klasse X (Objekt, Extender)' sagen, die mit ähnlichem Fehler behaftet sind.) 'Base .__ Basen__ + = (Extender,) + Base .__ Basen__ 'wird einfach werfen '' E 'Deallocator unterscheidet sich von' Objekt '', das ist ein weiterer Fehler insgesamt, aber immer noch ein Fehler. – driax

+0

@driax: Ja, danke für die Erklärung. – unutbu

+2

Für Zukünftige Referenz, es gibt ein offenes CPython-Problem bezüglich des Deallocator-Fehlers: https://bugs.python.org/issue672115 (seit 2003 geöffnet, halte also nicht den Atem an) – driax

Verwandte Themen