2016-05-08 12 views
1

Ich habe diese Klasse gemacht:Wie erzwinge ich eine Klasse?

class AudioSegmentCustom(AudioSegment): 

    def fade_override(self, seg, fade_len=100): 
     seg1, seg2 = AudioSegment._sync(self, seg) 
     final = seg1[:-fade_len] 
     a_fin = seg1[-fade_len:].fade(to_gain=-120, start=0, end=float('inf')) 
     a_fin *= seg2[:fade_len] 
     return (final + a_fin) + seg2[fade_len:] 

Das Problem, das ich mit Blick auf bin, wenn ich einige AudioSegmentCustom Variablen zu erstellen, wenn ich „add“ sie, die add Operation liefert seinen ursprünglichen Typ parent = AudioSegment

So der folgende Code nicht funktioniert:

final = AudioSegmentCustom.from_mp3(mp3_src) + AudioSegment.from_mp3(mp3_other) 
final = final.fade_override(...blabla...) 

weil ich:

'AudioSegment' object has no attribute 'fade_override' 

... obwohl ich mit einem AudioSegmentCustom Objekt begonnen habe, beende ich mit AudioSegment "nur" Objekt. Wie wird der Typ eines neu erstellten Objekts "erzwungen"?

Für den Fall, müssen Sie es:

class AudioSegment(object): 
    def __add__(self, arg): 
     if isinstance(arg, AudioSegment): 
      return self.append(arg, crossfade=0) 
     else: 
      return self.apply_gain(arg) 
+0

Sie sollten wahrscheinlich den Code für 'AudioSegment .__ add__' hinzufügen. –

+0

Es gibt nur ein AudioSegment-Objekt zurück. Warum brauchen Sie es? Anyway nur aktualisiert meine Frage –

+0

Da wäre ein Weg, es zu zwicken, so dass es Instanzen der gleichen Klasse wie 'self' erstellt. Wenn Sie es nicht ändern wollen, müssen Sie sicherlich eine separate 'AudioSegmentCustom .__ add__' Methode schreiben oder das' AudioSegmentCustom' an anderer Stelle erstellen. –

Antwort

1

Sieht aus wie das Problem AudioSegment._spawn() ist.

Es gibt unbedingt eine reine AudioSegment Instanz zurück. Da es sich um eine normale Methode ist, können Sie es in AudioSegmentCustom außer Kraft setzen:

def _spawn(self, data, overrides={}): 
    """ 
    Creates a new audio segment using the metadata from the current one 
    and the data passed in. Should be used whenever an AudioSegment is 
    being returned by an operation that would alters the current one, 
    since AudioSegment objects are immutable. 
    """ 
    # accept lists of data chunks 
    if isinstance(data, list): 
     data = b''.join(data) 

    # accept file-like objects 
    if hasattr(data, 'read'): 
     if hasattr(data, 'seek'): 
      data.seek(0) 
     data = data.read() 

    metadata = { 
     'sample_width': self.sample_width, 
     'frame_rate': self.frame_rate, 
     'frame_width': self.frame_width, 
     'channels': self.channels 
    } 
    metadata.update(overrides) 
    return self.__class__(data=data, metadata=metadata) 

Die Kopie & Paste sicherlich keine gute Praxis, aber es macht den Job.

Beachten Sie jedoch, dass es führt eine Asymmetrie, weil AudioSegmentCustom + AudioSegment ein AudioSegmentCustom zurückkehrt, während AudioSegment + AudioSegmentCustom eine AudioSegment zurückgibt. Dieses - mehr - kann behoben werden, indem zusätzlich __radd__() in AudioSegmentCustom bereitgestellt wird. Es wird vor AudioSegment.__add__() aufgerufen werden.

+1

Sie können '__radd __()' definieren, um diese Asymmetrie zu vermeiden: wie [die Dokumente] (https://docs.python.org/2/reference/datamodel.html#object.__radd__) darauf hinweisen, in dem Fall, in dem Der rechte Operand ist eine Unterklasse des linken, Python wird zuerst das '__radd__' des Rechtes aufrufen. –

+0

@DanielRoseman Vielen Dank, dass Sie darauf hingewiesen haben. Hinzugefügt. – dhke

+0

Die [entsprechende Änderung] (https://github.com/jiaaro/pydub/commit/40bd30c81e12664d849de78fcf8bd43359d16c72) wurde in pydub zusammengeführt und der Hack sollte für zukünftige Versionen nicht mehr benötigt werden. – dhke

Verwandte Themen