2015-06-18 7 views
5

Mein spezifischer Anwendungsfall ist Ich versuche, pathlib.Path Unterklasse zu bilden. Ich möchte in der Lage sein, einige Funktionen hinzuzufügen oder zu überschreiben, aber ich möchte auch den gesamten Pfad erben. Pfad hat eine __new__ und in ihm hat:Wie wird eine Klasse abgeleitet, die ein __new__ hat und auf dem Wert von cls beruht?

if cls is Path: 
    cls = WindowsPath if os.name == 'nt' else PosixPath 

Mit anderen Worten Pfad erfordert es die richtige Klasse übergeben. Das Problem ist, ich weiß nicht, wie ich meine Klasse erstellen und Path.__new__ mit cls == Path aufrufen.

Ich habe viele Dinge ausprobiert und jedes gibt mir ein anderes Problem. Dieser gibt mir AttributeError: type object 'RPath' has no attribute '_flavour', weil ich versuche, die Elternklasse zu überschreiben.

Python3:

class RPath(Path): 
    def __new__(cls, basedir, *args, **kwargs): 
     return Path.__new__(cls, *args, **kwargs) 

    def __init__(self, basedir, *pathsegs): 
     super().__init__() 
     self.basedir = basedir 

    def newfunction(self): 
     print('Something new') 

Und dieser gibt kehrt ein Path-Objekt, und daher nicht erlaubt, mir meine Überschreibungen zu tun.

def __new__(cls, basedir, *args, **kwargs): 
    return Path.__new__(Path, *args, **kwargs) 

Ich habe auch versucht, verschiedene Verwendungen von super(), ohne Erfolg.

Dies scheint wie es sollte ziemlich einfach sein. Was vermisse ich?

Update: Was versuche ich zu erreichen? Insbesondere möchte ich class RPath(basedir, *pathsegments) machen:

rpath=RPath('\root\dir', 'relpath\path2\file.ext) 
assert rpath.basedir == '\root\dir' # True 
rpath.rebase('\new_basedir') 
assert rpath.basedir === '\newbasedir' # True 
# And while I'm at it 
assert rpath.str == str(rpath) # make str a property == __str__(self) 
+0

Was ist die genaue Funktionalität, die Sie in __new__ einfügen möchten? – Meitham

+0

Sie müssen hier klarstellen, was Sie zu tun versuchen. Die Funktionalität von 'Path .__ new__', die Sie beibehalten möchten, wird eine * andere Klasse * instanziieren. Wenn Sie also diesen Teil des Codes ausführen lassen würden, würde Ihre Unterklasse verschwinden. –

+0

Aktualisiert oben. Tut mir leid, ich war nicht klar genug. Genauer gesagt ruft pathlib nicht '__init__' auf. Irgendwo möchte ich das erste Argument 'class RPath (baselib, * pathsegments) nehmen und' self.baselib = baselib' in '__new__' oder in meinem eigenen' _init__' setzen. –

Antwort

2

Ich glaube nicht, dass in der üblichen Art und Weise möglich sein, geht. Aber selbst wenn Sie es tun könnten, würde es nicht funktionieren, denn was Path tut, gibt auch keinen einfachen Pfad zurück, es gibt eine Unterklasse zurück (WindowsPath oder PosixPath). Ihre Überschreibungen auf Path werden nicht wirksam, denn wenn Sie Path.__new__ erben konnten, würde es immer noch beispielsweise einen WindowsPath zurückgeben, und WindowsPath erbt von Path, nicht von Ihrer benutzerdefinierten Pfadunterklasse.

Es scheint pathlib.Path hat eine idiosynkratische Klassenstruktur, und Sie müssen einige spezielle Arbeit tun, um es zu duplizieren. Bei einer ersten Schätzung müssten Sie Ihre eigenen Unterklassen von WindowsPath und PosixPath erstellen und dann eine Pfad-Unterklasse erstellen, die eine dieser Instanzen anstelle von sich selbst instanziiert.

0

Hier ist eine Lösung, obwohl es keine Vererbung verwendet. Ich vermute immer noch, dass es einen einfachen, einfachen Vererbungsweg gibt (obwohl ich BrenBarns Antwort für die andere Seite sehe).

Diese Methode verwendet Zusammensetzung. Der Schlüssel verwendet __getattr__ und getattr(), um automatisch alle Anforderungen zu delegieren, die nicht in der Wrapperklasse gefunden wurden. Hier ein Beispiel:

class RPath(object): 
    def __init__(self, basedir, *pathsegs): 
     self.p = Path(*pathsegs) 
     self.basedir = basedir 

    # Override existing behavior 
    def __eq__(self, other): 
     return type(other) is RPath and self.basedir == other.basedir and self.p == other.p  

    # Add new behavior 
    def cp(self): 
     return self.basedir/self.p  

    # Everything not found here, automatically delegate to Path 
    def __getattr__(self, attr): 
     return getattr(self.cp, attr) 
0

Denken Sie daran, dass Sie unter absolut keine Verpflichtung tatsächlich Ihre Superklasse __new__ oder __init__ zu nennen. Die einzige Einschränkung besteht darin, dass Sie letztendlich object.__new__(cls) aufrufen, um ein Objekt vom Typ cls zuzuordnen.

Also, kopieren Sie einfach die relevante Logik aus Ihrer Superklasse __new__ in Ihre eigenen.

Verwandte Themen