2012-10-11 3 views
5

Nach einigem Lesen habe ich mich mit zwei verschiedenen Ansätzen herumgeschlagen, um eine Liste von Argumenten an eine Funktion zu übergeben. Ich lese einige Hinweise. Das ist, was ich bisher herausgefunden:Der beste Ansatz zum Übergeben und Behandeln von Argumenten zur Funktion

Actual Code:

Datei caller.py:

import worker 
worker.version_check(iserver,login,password,proxyUser,proxyPass, 
    proxyServer,packageInfo) 

worker.version_get(iserver,login,password,proxyUser,proxyPass, 
    proxyServer,packageInfo) 

worker.version_send(iserver,login,password,proxyUser,proxyPass, 
    proxyServer,packageInfo) 

Datei: worker.py:

def version_check(iserver,login,password,proxyUser,proxyPass,proxyServer,service): 
    #code and more code 

def version_get(iserver,login,password,proxyUser,proxyPass,proxyServer,service): 
    #code and more code 

def version_send(iserver,login,password,proxyUser,proxyPass,proxyServer,service): 
    #code and more code 

Und jetzt habe ich:

Datei caller.py:

import worker 
args = (env, family, host, password, prefix, proxyServer, 
     proxyUser, proxyPass, option, jokerVar 
     ) 
worker.version_check(*args) 
worker.version_get(*args) 
worker.version_send(*args) 

Datei: worker.py:

def version_check(*args): 
    env = args[0] 
    family = args[1] 
    host = args[2] 
    password = args[3] 
    prefix = args[4] 
    proxyServer = args[5] 
    proxyUser = args[6] 
    proxyPass = args[7] 
    option = args[8] 
    jokerVar = args[9] 

    #code and more code 

def version_get((*args): 
    env = args[0] 
    family = args[1] 
    host = args[2] 
    password = args[3] 
    prefix = args[4] 
    proxyServer = args[5] 
    proxyUser = args[6] 
    proxyPass = args[7] 
    option = args[8] 
    jokerVar = args[9] 

    #code and more code 

def version_send(*args): 
    env = args[0] 
    family = args[1] 
    host = args[2] 
    password = args[3] 
    prefix = args[4] 
    proxyServer = args[5] 
    proxyUser = args[6] 
    proxyPass = args[7] 
    option = args[8] 
    jokerVar = args[9] 

    #code and more code 

Mit dem alten Konzept (Ist-Code) Ich glaube, dass es mehr „freundlich“ ist nur eine Funktion in einer Zeile zu nennen (wie Sie auf worker.py sehen). Aber mit dem neuen Ansatz denke ich, dass der Code umfangreicher wird, weil ich für jede Funktion dieselben Variablen definieren muss. Aber ist das die beste Praxis? Ich lerne immer noch Python auf einer langsamen Kurve, also, Entschuldigung für irgendwelche Fehler im Code.

Und eine wichtige Sache, die meisten Variablen werden aus einer Datenbank abgerufen, so dass sie nicht staktisch sind.

+5

Im Allgemeinen, wenn Sie mit Funktionen mit, dass viele Argumente am Ende, müssen Sie über Ihr Design etwas mehr denken. Wäre das Übergeben eines Objekts besser als die vielen Argumente? –

+0

@MartijnPieters Es ist möglich, mir ein Beispiel zu schicken? In der Zwischenzeit werde ich versuchen, es auch auf anderem zu finden. und Python-Dokumentation. –

+1

Was bedeutet die Menge der Argumente? Kann das benannt werden? Wenn dies der Fall ist, machen Sie es zu einem namedtuple oder einer benutzerdefinierten Klasse, um diese Informationen zu speichern, dann müssen Sie ein Objekt anstelle von x separaten Argumenten übergeben. –

Antwort

6

ich wirklich empfehlen nicht funktioniert wie def version_check(*args):, wenn Sie speziell definieren Notwendigkeit zu. Schnell, ohne die Quelle zu lesen: In welcher Reihenfolge sind die Argumente? Wie geben Sie einen Standardwert für den ProxyServer an? Denken Sie daran, "explizit ist besser als implizit".

Das eine Mal, ich routinemäßig von dieser Regel abweichen, wenn ich wie eine andere Funktion bin Verpackung:

def foo(bar): 
    print 'Bar:', bar 

def baz(qux, *args): 
    print 'Qux:', qux 
    foo(*args) 

würde ich nie tun es für so ein einfaches Beispiel, aber foo annehmen, ist eine Funktion von a Paket von Drittanbietern außerhalb meiner Kontrolle mit vielen Standardwerten, Schlüsselwortargumenten usw. In diesem Fall würde ich eher das Argument parsing an Python stochern, als es selbst zu versuchen.

Persönlich würde ich so als eine Klasse schreiben:

class Worker(object): 
    def __init__(iserver,login,password,proxyUser,proxyPass,proxyServer,service): 
     self.iserver = iserver 
     self.login = login 
     self.password = password 
     self.proxyUser = proxyUser 
     self.proxyPass = proxyPass 
     self.proxyServer = proxyServer 
     self.service = service 

    def version_check(self): ... 

    def version_get(self): ... 

    def version_send(self): ... 

Und dann in dem Client schreiben:

from worker import Worker 

w = Worker(iserver,login,password,proxyUser,proxyPass,proxyServer,service) 
w.version_check() 
w.version_get() 
w.version_send() 

Wenn Sie wirklich Funktionen mit vielen Argumenten schreiben müssen stattdessen diesen Zustand in einer Klasse zu kapseln - was eine eher pythonische Art ist, dies zu tun - dann betrachte den namedtuple-Datentyp aus neueren Python-Versionen.Sie können ein Tupel angeben, in dem Elemente nach Schlüsselwort adressierbar sind und für einen sehr sauberen, eleganten Code sorgen können.

+0

+1! Das ist eine großartige Antwort. Sie gaben die gleiche Lösung, die ich gegeben hätte (kapseln die Funktionen und Daten in einer Klasse) und gaben eine sehr klare Erklärung dafür, warum die ursprüngliche Version nicht so gut ist. – Blckknght

+0

+1 Sie könnten auch [mehr als ein Objekt erstellen] (http://stackoverflow.com/questions/12844963/best-approach-to-pass-and-handle-arguments-to-function#comment17382149_12844963) – jfs

+0

@Blckknght Danke ! Ich versuche. :-) –

0

Sie können ein Objekt erstellen oder eine Klasse definieren. z.B.

Datei caller.py:

import worker 

info=object() 
info.env=0 
info.family='something' 
info.host='something' 
info.password='***' 
info.prefix='' 
info.proxyServer='' 
info.proxyUser='' 
info.proxyPass='' 
info.option='' 
info.jokerVar='' 

worker.version_check(info) 
worker.version_get(info) 
worker.version_send(info) 

Datei worker.py:

def version_check(info): 
    #you may access values from info 
    #code and more code 

def version_get(info): 
    #code and more code 

def version_send(info): 
    #code and more code 
+0

Sie können keine willkürlichen Attribute auf 'Objekt' direkt setzen. Statt dessen könnte 'class Info: pass' verwendet werden. Wie auch immer, diese Approch ist nicht besser als einfach Schlüsselwortargumente zu verwenden, siehe [Element 1 in @Francis 'Antwort] (http://stackoverflow.com/a/12847386/4279) – jfs

2

Es gibt viele Ansätze, abhängig davon, was diese Argumente darstellen.

  1. Wenn sie nur eine Grab-Bag von Argumenten sind (vor allem, wenn einige optional sind), verwendet Schlüsselwort Argumente:

    myargs = {'iserver':'server','login':'username','password':'Pa2230rd'} 
    version_get(**myargs) 
    
  2. Wenn sie etwas, was mit ihrem eigenen Zustand darstellt, dann Klassen verwenden:

    1. Wenn die Argumente einen einzigen Zustand, dass Ihr func darstellen gen ändern, und die Argumente in der Objektkonstruktor akzeptieren und Ihre version_* Methoden Funktionen dieser Klasse machen:

      class Version(object): 
          def __init__(self,iserver,login,password, 
             proxyUser,proxyPass,proxyServer,service): 
           self.iserver = iserver 
           self.login = login 
           #etc 
          def check(self): 
           self.iserver 
          def get(self): 
           pass 
          #etc 
      myversion = Version('iserver','login',...) 
      myversion.check() 
      
    2. Wenn Sie diese Argumente repräsentieren eine Art von Ressource haben, dass Ihre Funktionen nur in diesem Fall verwenden verwenden, um eine eigene Klasse, und als Objektparameter auf Ihre Funktionen liefern:

      class Connection(Object): 
          def __init__(self, iserver, ...): 
           self.iserver # etc 
      
      myconn = Connection('iserver',...) 
      
      version_check(myconn) 
      
    3. Höchstwahrscheinlich wahrscheinlich~~POS=HEADCOMP das sind zwei verschiedene Ressourcen und sollten zwei Klassen sein. In diesem Fall können Sie diese Ansätze kombinieren:

      #Connection() class as above 
      class Version(object): 
          def __init__(self, connection): 
           self.connection = connection 
          def check(self): 
           self.connection.iserver # .... 
      
      myconn = Connection('iserver', ...) 
      conn_versioner = Version(myconn) 
      conn_versioner.check() 
      
    4. Möglicherweise Ihre Argumente repräsentieren mehr als ein Objekt (zB eine Verbindung und ein transparentes Proxy-Objekt) In diesem Fall versuchen, ein Objekt mit der kleinsten Öffentlichkeit zu schaffen Schnittstellenmethoden wie version_* würden den Zustand, der durch die anderen Argumente repräsentiert wird, unter Verwendung der Objektkomposition benötigen und einkapseln.

      Zum Beispiel, wenn Sie Proxy-Verbindungen haben, können Sie eine Connection() Klasse erstellen, die nur weiß, über Server, Login und Passwort und eine ConnectionProxy() Klasse, die alle Methoden eines Connection hat, sondern nach vorn zu einem anderen Connection-Objekt. Dies ermöglicht Ihnen, die proxy* Argumente zu trennen, und bedeutet, dass Ihre version_* Funktionen können nicht wissen, ob sie einen Proxy verwenden oder nicht.

  3. Wenn Ihre Argumente einfach Zustand sind und haben keine eigenen Methoden, um sie betrachten wir eine namedtuple() verwenden. Dies funktioniert wie ein intelligenteres Tupel (einschließlich Tupel-Entpacken, Slicen usw.) und hat nur minimalen Einfluss auf Ihren bestehenden Code, während er noch benutzerfreundlicher ist.

    Connection = namedtuple('Connection', 'iserver login password etc') 
    myconn = Connection('iserver', 'loginname', 'passw3rd') 
    version_check(*myconn) 
    
Verwandte Themen