2015-04-25 20 views
11

Ich möchte eine Funktion in Python schreiben, die eine Scheibe als Parameter nimmt. Idealerweise würde ein Benutzer in der Lage sein, die Funktion aufzurufen, wie folgt:Wie schreibe ich eine Funktion, die eine Scheibe nimmt?

foo(a:b:c) 

Leider ist diese Syntax nicht von Python zulässig ist - die Verwendung von a:b:c nur innerhalb [] erlaubt ist, nicht ().

Ich sehe daher drei Möglichkeiten für meine Funktion:

  1. den Benutzer erfordern eine Scheibe "Konstruktor" zu verwenden (wo s_ wirkt wie the version provided by numpy):

    foo(slice(a, b, c)) 
    foo(s_[a:b:c]) 
    
  2. Setzen Sie die Logik Meine Funktion in eine __getitem__ Methode:

    foo[a:b:c] 
    
  3. Aufgeben versuchen, ein Stück zu nehmen und nehmen starten, zu stoppen und individuell Schritt:

    foo(a, b, c) 
    

Gibt es eine Möglichkeit die ursprüngliche Syntax zur Arbeit zu kommen? Wenn nicht, welche der Workaround-Syntax wäre zu bevorzugen? Oder gibt es eine andere, bessere Option?

+3

Ich Verwendung Start verwenden würde, stoppen und Einstellschritt Standard Werte –

+2

Wie basiert das hauptsächlich auf Meinungen? Dies ist eine vollständig gültige Frage. –

+0

Ich sehe überhaupt keinen Nachteil darin, 'foo (a, b, c)' anstelle von 'foo (a: b: c)' zu verwenden. – TigerhawkT3

Antwort

10

Überraschen Sie Ihre Benutzer nicht.

Wenn Sie die Slicing-Syntax konsistent mit dem verwenden, was ein Entwickler von einer Slicing-Syntax erwartet, erwartet derselbe Entwickler eckige Klammern, d. H. Eine __getitem__()-Methode.

Wenn stattdessen das zurückgegebene Objekt nicht irgendwie ein Stück des ursprünglichen Objekts ist, werden die Leute verwirrt sein, wenn Sie bei einer __getitem__() Lösung bleiben. Verwenden Sie einen Funktionsaufruf foo(a, b, c), erwähnen Sie keine Slices, und weisen Sie optional Standardwerte zu, wenn dies sinnvoll ist.

0

Die Verwendung von [a:b:c] ist, wie Sie bemerken, eine Syntax-Sache. Der Interpreter löst sofort eine syntax error für (a:b:c) aus, bevor Ihr Code eine Chance hat, etwas mit den Werten zu tun. Es gibt keine Möglichkeit, diese Syntax zu umgehen, ohne den Interpreter neu schreiben zu müssen.

Es lohnt sich wenn man bedenkt, dass der Dolmetscher foo[a:b:c] zu

foo.__getitem__(slice(a,b,c)) 

Das slice Objekt übersetzt sich nicht sehr kompliziert ist. Es hat nur 3 Attribute (start, step, stop) und eine Methode indices. Es ist die getitem Methode, die diese Werte sinnvoll macht.

np.s_ und andere Funktionen/Klassen in np.lib.index_tricks sind gute Beispiele dafür, wie __getitem__ und slice können (oder vereinfachen) Indizierung erweitern verwendet werden. Zum Beispiel sind diese äquivalent:

np.r_[3:4:10j] 
np.linspace(3,4,10) 

In Bezug auf die foo(a,b,c) Syntax, die sehr häufig np.arange() es verwendet.Ebenso wie range und xrange. Daher sollten Sie und Ihre Benutzer damit vertraut sein.

Da die Alternativen alle am Ende geben Sie die start/step/stop Trio von Werten, sind sie funktionell gleichwertig (in Geschwindigkeit). Die Auswahl hängt also von den Vorlieben und der Vertrautheit der Benutzer ab.

Während Ihre Funktion a:b:c Notation nicht direkt annehmen kann, kann sie geschrieben werden, um eine Vielzahl von Eingaben zu verarbeiten - ein Slice, 3 Positionsargumente, ein Tupel, ein Tupel von Slices (ab s_) oder Schlüsselwortargumente. Und nach der grundlegenden numpy Indizierung konnten Sie zwischen Tupeln und Listen unterscheiden.

2

Scheiben ergeben mehr Sinn, wenn sie als ein Stück von etwas ausgedrückt werden. Eine andere Alternative besteht darin, objektorientierter zu sein: Erstelle ein temporäres Objekt, das dein Stück von etwas repräsentiert, und stelle deine Funktion als eine Methode dar.

Zum Beispiel, wenn Ihre Funktion ist wirklich:

foo(bar, a:b:c) 

oder

bar.foo(a:b:c) 

dann können Sie diese ersetzen mit:

bar[a:b:c].foo() 

Wenn bar[a:b:c] bereits eine andere Bedeutung hat, dann kommen Sie mit einem anderen Namen baz und tun:

Es ist schwer, überzeugende Beispiele ohne einen echten Kontext zu geben, weil Sie verwandte Dinge mit Namen benennen wollen, die intuitiv Sinn machen, Ihnen eindeutigen Code schreiben lassen und relativ kurz sind.

Wenn Sie wirklich nur eine Funktion auf einem eigenen Betrieb auf einer Scheibe zu schreiben, dann entweder:

  1. Ihre Funktion ändert eine Scheibe, eine andere Scheibe Rückkehr:

    bar[foo(a:b:c)] 
    

    Wenn Dies ist der Fall, egal welche gültige Syntax Sie wählen, wird etwas verwirrend aussehen. Sie möchten wahrscheinlich keine Slices verwenden, wenn Sie auf eine breite Zielgruppe von Python-Programmierern abzielen.

  2. Ihre Funktion arbeitet wirklich auf ein Stück der ganzen Zahlen, so können Sie diese explizit mit einem temporären Objekt machen können:

    the_integers[a:b:c].foo() 
    
Verwandte Themen