2010-10-29 4 views
6

Ich habe eine Funktion, wo ich verschiedene Ausgabezeichenfolgen für ein anderes Programm, das ich aufrufen muss, je nachdem, welchen Typ es will.Was ist die kanonische Art, verschiedene Arten in Python zu behandeln?

Grundsätzlich benötigt das aufgerufene Programm ein Befehlszeilenargument, das ihm mitteilt, mit welchem ​​Typ es aufgerufen wurde.

Glücklicherweise fand ich this answer auf SO auf, wie man eine Variable für den Typ überprüft. Aber ich habe gemerkt, dass die Leute auch Einwände erhoben haben, dass das Suchen nach Typen ein "nicht objektorientiertes" Design verrät. Also, gibt es eine andere Möglichkeit, vermutlich mehr "objektorientierte" Art, dies zu handhaben, ohne explizit nach Typ zu suchen?

Der Code habe ich jetzt geht ungefähr so:

def myfunc(val): 
    cmd_type = 'i' 
    if instance(val, str): 
     cmd_type = 's' 

    cmdline = 'magicprogram ' + cmd_type + ' ' + val 
    Popen(cmdline, ... blah blah) 
    ... 

, die ganz gut funktioniert, aber ich wollte nur wissen, ob es irgendeine Technik ist von Ich bin nicht bewusst.

+0

Wie geben Sie alles mit einem Typ in der Befehlszeile ein? – geoffspear

+0

@Wobble, ich habe ein Beispiel hinzugefügt. Ich erkannte, dass die Frage nicht sehr offensichtlich war. Hoffe es ist jetzt besser. –

+0

Wie wird myfunc aufgerufen? Ich würde vorschlagen, zwei verschiedene Funktionen zu haben, die eine andere Art von Argument erwarten, und dann eine private Funktion des unteren Teils der Funktion zu machen, die Sie mit geeigneten Argumenten von jeder der früheren Funktionen aufrufen. – teukkam

Antwort

3

Ich glaube nicht, Doppel Dispatching oder Multimethoden besonders relevant sind, noch haben viel mit den Einwänden zu tun, die Menschen so zu, dass andere hatten zu beantworten.

Es ist nicht überraschend, dass Sie Objekte (und entsprechende Klassen) einführen müssen, um das, was Sie tun, objektorientierter zu machen. Würde man jeden Wert zu einer Instanz einer Klasse machen, dann würde man praktisch aufhören, den Typ zu überprüfen. Die Änderungen an Ihrem Beispielcode unten zeigen eine sehr einfache Möglichkeit, dies hätte getan werden können:

class Value(object): 
    """ Generic container of values. """ 
    def __init__(self, type_, val): 
     self.type = type_ # using 'type_' to avoid hiding built-in 
     self.val = val 

def myfunc(val): 
    # Look ma, no type-checking! 
    cmdline = 'magicprogram {obj.type} {obj.val}'.format(obj=val) 
    print 'Popen({!r}, ... blah blah)'.format(cmdline) 
    # ... 

val1 = Value('i', 42) 
val2 = Value('s', 'foobar') 

myfunc(val1) # Popen('magicprogram i 42', ... blah blah) 
myfunc(val2) # Popen('magicprogram s foobar', ... blah blah) 

Es wäre noch mehr objektorientiert, wenn es Methoden waren in der Value Klasse seine Attribute indirekt zugreifen, aber nur tun, das oben genannte wird die berüchtigte Typ-Überprüfung los. Ein objektorientierter Entwurf würde wahrscheinlich eine andere Unterklasse für jede Art von Value haben, die alle einen gemeinsamen Satz von Methoden für Clients verwenden, wie myfunc(), um daraus Informationen zu erzeugen, zu manipulieren und zu extrahieren.

Ein weiterer Vorteil der Verwendung von Objekten ist, dass Sie myfunc() nicht ändern müssen, wenn/wenn Sie Unterstützung für einen neuen Typ von "Value" zu Ihrer Anwendung hinzufügen - wenn Ihre Abstraktion der Essenz eines "Value" ist ein guter, das ist.

5

Sie könnten Double Dispatch oder Multimethods verwenden.

+1

Und in Python wäre das http://www.artima.com/weblogs/viewpost.jsp?thread=101605 und http://en.wikipedia.org/wiki/Multiple_dispatch#Python ich vermute. Vielen Dank! –

+0

Für meine Zwecke, ich denke, ich werde bei der Überprüfung des Typs bleiben, aber dies war eine sehr aufschlussreiche Erfahrung, sowohl für Python funktioniert und wie Menschen über diese Probleme denken. Akzeptieren Sie Ihre Antwort, da sie meine Frage so genau beantwortet, wie sie formuliert wurde. –

1

Dies ist mehr ein Engineering in der großen Frage als, wie man eine kleine Funktion zu entwerfen. Es gibt viele verschiedene Wege, um damit umzugehen, aber sie gehen mehr oder weniger auf denselben allgemeinen Denkprozess zurück. Zurück, wo der Typ von val bekannt ist, sollte angegeben werden, wie es in eine Befehlszeile arg übersetzt werden soll. Wenn ich es wäre, würde ich wahrscheinlich eine Klasse machen, die eine To Command Line Funktion hat, die das Richtige getan hat. Sie könnten einer Variablen auch eine typspezifische myfunc-Funktion zuweisen und diese dann bei Bedarf aufrufen.

bearbeiten: Um die letzte Version etwas entlang der Linien von

Val = "a string" 
myfunc = myfuncStringVersion 

mehr oder weniger das gleiche tun würden Sie mit Einwickeln val in einer Klasse nur ausgebrochen, in einen Wert und Funktion erklären, da können Sie nicht möchte val in einer Klasse umbrechen.

+0

"Sie könnten auch eine typspezifische Myval-Funktion einer Variablen zuweisen und diese dann bei Bedarf aufrufen." <---- Ich lese es immer und immer wieder, ich verstehe es nicht. –

+0

@Amigable Clark Kant Sorry, hoffentlich macht es jetzt mehr Sinn. – stonemetal

3
But I noticed how people also raised objections, 
that checking for types betrays a "not object oriented" design 

Eigentlich ist es Duck typing style genannt („Wenn es aussieht wie eine Ente und quakt wie eine Ente, muss es eine Ente sein.“), Und es ist die Python-Sprache, die diese Art der Programmierung empfehlen.

und mit Ente eingeben EAFP etwas Aufruf kommen (Einfachere Vergebung zu bitten als Permission)

presumable more "more object oriented" way of handling this without 
    explicitly checking for type? 

Sie mehr pythonic bedeuten, im Grunde, was mehr in Ihrem Fall pythonic sein wird, ist so etwas wie diese:

def myfunc(val): 
    cmd_type = 'i' 

    # forget about passing type to your magicprogram 
    cmdline = 'magicprogram %s ' % val 
    Popen(cmdline, ... blah blah) 

und in Ihrem magicprogram (ich weiß nicht, ob es Ihr Skript oder ... ist), und weil in allen Fällen Ihr Programm eine Zeichenfolge erhalten wird, versuchen Sie es einfach zu konvertieren, was auch immer Skript akzeptieren t;

from optparse import OptionParser 

# .... 

if __name__ == '__main__': 

    parser = OptionParser(usage="blah blah") 

    # ... 
    (options, args) = parser.parse_args() 

    # Here you apply the EAFP with all type accepted. 
    try: 
     # call the function that will deal with if arg is string 
     # remember duck typing. 
    except ... : 
     # You can continue here 

Ich weiß nicht, was all Ihren Code ist, aber Sie können das Beispiel folgen darüber mehr pythonic ist, und denken Sie daran jede Regel hat ihre Ausnahme vielleicht der Fall ist eine Ausnahme und Sie werden mit Typ besser sein Überprüfung.

Hoffe, dies wird die Dinge für Sie klären.

+0

Ok, in meinem Fall ist magicprogram NET-SNMP, und das Ändern ist keine Option. Aber danke für die Gedanken sowieso. –

+0

Ahh ok, aber ich hoffe, dass meine Antwort klare Dinge über die Python-Philosophie hat; Duck Typisierung und EAFP :) – mouad

+0

"Es hat etwas zu tun Duck Typ eingeben, und es ist Python Philosophie und nicht objektorientiert" ist nicht wahr und erfordert nicht Duct Typing. Es ist wahr für jede Sprache, die [Polymorphismus] (http://en.wikipedia.org/wiki/Polymorphism_in_object- oriented_programming) unterstützt und viele (die meisten?) OO tun, glaube ich. – martineau

Verwandte Themen