2017-09-26 6 views
1

In Python (3) möchte ich eine abgeleitete Klasse dynamisch aus mehreren Basisklassen erstellen.Wie wählt man die Python-Basisklasse dynamisch?

Konkretes Beispiel: In selenium, um GUI-basierte Tests ausführen, können Sie einen Treiber von zB Firefox oder Chrome auf folgende Weise einleiten:

driver = webdriver.Firefox() 
driver = webdriver.Chrome() 

Jetzt möchte ich eine abgeleitete Klasse erstellen, auf die Zusätzliche Funktionalitäten werden hinzugefügt. So etwas wie

class MyDriver(webdriver.Firefox): 
    def find_button_and_click_on_it_no_matter_what(self, params): 
     ... 

Aber die Basisklasse kann entweder die firefox Fahrer oder Chrom driver sein. Ich fand here etwas im Zusammenhang, aber es scheint nicht zu funktionieren:

class MyDriver(object): 
    def __new__(cls, base_type, *args, **kwargs): 
     return super(HBPDriver, cls).__new__(base_type, *args, **kwargs) 

    def __init__(self): 
     pass 

Aufruf dieser Befehl

driver = mydriver.MyDriver(webdriver.Firefox())  

einen Fehler

TypeError: object.__new__(X): X is not a type object (WebDriver) 

gibt Wie es richtig zu machen? Und wie man __init__ auf der abgeleiteten Klasse ... aufruft?

Ich hoffe, es ist klar, was ich erreichen will ...

Antwort

2

Bis Sie __new__ nennen es zu spät ist, um die Klasse zu wählen zu instanziiert; __new__ ist ein Attribut der Klasse. Stattdessen müssen Sie eine triviale Werk Funktion:

def my_driver(cls, *args, **kwargs): 
    class NewThing(cls): 
     ... 
    return NewThing(*args, **kwargs) 

ff = my_driver(webdriver.Firefox) 

Eine weitere Option ist die Basisklasse mit einem Ausdruck zu definieren:

if ...: 
    base = webdriver.Firefox 
elif ...: 
    base = webdriver.Chrome 
class MyDriver(base): 
    ... 

Eine dritte Möglichkeit ist die class Anweisung zu überspringen und type direkt verwenden, obwohl ich würde dies nicht empfehlen, es sei denn, der Hauptteil der Klassenanweisung würde leer sein.

class MyDriver(base): 
    pass 

entspricht MyDriver = type('MyDriver', (base,), {}).

+0

Tanks für die Optionen - aber wo/wie kann ich zusätzliche Klassenmethoden in der ersten Option definieren? – Alex

+0

Die erste Option ist gewissermaßen ein Wrapper um die beiden anderen (außer dass sie keine Unterklasse definiert, sondern das Objekt instanziiert hat). Ich habe es aktualisiert, um zu zeigen, wie es die gleiche Idee wie im zweiten Beispiel verwendet, um eine neue Klasse lokal in der Funktion zu definieren. – chepner

+0

Ah ich sehe was du meinst. Ich würde sagen, dies sind die gleichen Möglichkeiten, dies zu tun. Wie auch immer, dein Vorschlag scheint zu funktionieren ... – Alex

Verwandte Themen