2012-10-11 3 views
5

読んだ後、関数の引数のリストを渡すために2つの異なる方法で苦労していました。私はいくつかの適応症を読んだ。それは私がこれまでに考え出したものです:関数への引数を渡して処理するための最善のアプローチ

実際のコード:

ファイル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) 

ファイル: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 

そして今、私が持っている:

ファイル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) 

ファイル: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 

私はあなたがworker.py上で見ることができるように(1行だけの関数を呼び出すために、より「やさしい」であると信じて)。しかし、新しいアプローチを使用すると、各関数に対して同じ変数をすべて定義する必要があるため、コードがより広範囲になると思います。しかしこれはベストプラクティスですか?私はまだ遅いカーブでPythonを学んでいるので、コードの間違いをおかしなさい。

重要なことは、ほとんどの変数はデータベースから取得されるため、スタティックではありません。

+5

は一般的に、あなたはいくつかのより多くのあなたのデザインを考える必要があります。オブジェクトを渡すことは、その多くの議論よりも良いでしょうか? –

+0

@MartijnPieters私に例を送ることは可能ですか?私はそれをs.oでも見つけようとします。 Pythonのドキュメント。 –

+1

引数の集合は何を表していますか?それは名前を付けることができますか?そうであれば、その情報を保持する名前付きタプルまたはカスタムクラスにすると、x個の独立した引数の代わりに1つのオブジェクトを渡します。 –

答えて

6

私は本当に、特にあなたの場合を除きdef version_check(*args):のような関数を定義することはお勧めしません必要にします。素早く、ソースを読まずに:引数の順序は?どのようにproxyServerのデフォルト値を指定しますか?覚えておいて、 "明示的は暗黙的に優れています"。

のように私は別の関数をラップしていたとき、私は日常そのルールから逸脱し1時間は次のとおりです。私は、このような単純な例のためにそれを行うませんが、fooがから関数であると仮定しないだろう

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

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

私のコントロールの外にあるサードパーティ製のパッケージでは、デフォルトやキーワード引数などがたくさんあります。その場合、Pythonに引数をパースするのはむしろ自分で試してみてください。

個人的に、私のようなクラスとしてそれを記述します

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): ... 

そしてクライアントで、書き込み:

from worker import Worker 

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

あなたは本当に代わりに、引数のたくさんの機能を記述する必要がある場合その状態をクラスにカプセル化するのが一般的なPythonの方法ですが、最近のPythonバージョンのnamedtupleデータ型を考えてみましょう。これは、項目がキーワードでアドレス指定可能なタプルを指定し、非常にクリーンでエレガントなコードを作ることができます。

+0

+1!これは素晴らしい答えです。あなたは私が与えたと同じ解決策を与え(クラス内の関数とデータをカプセル化する)、元のバージョンがなぜそれほど良くないのかについての非常に明確な説明を与えました。 – Blckknght

+0

+1 [複数のオブジェクトを作成する]こともできます(http://stackoverflow.com/questions/12844963/best-approach-to-pass-and-handle-arguments-to-function#comment17382149_12844963) – jfs

+0

@Blckknghtありがとう!私は試してみる。 :-) –

0

インスタンスを作成したり、クラスを定義することができます。例えば

ファイル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) 

ファイル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

'object'に任意の属性を直接設定することはできません。代わりに 'class Info:pass'を使うことができます。とにかくこの約束は単にキーワード引数を使う以外にはありません。@Francisの答えのアイテム1(http://stackoverflow.com/a/12847386/4279) – jfs

2

これらの引数が何を表しているかによって、多くのアプローチがあります。その後、彼らは自身の状態でいくつかのことを表している場合

myargs = {'iserver':'server','login':'username','password':'Pa2230rd'} 
version_get(**myargs) 
  • 、:

    1. 彼らは、引数のちょうど福袋ある場合(一部はオプションである場合は特に)、キーワード引数を使用引数はそのあなたのFUNC単一の状態を表す場合

      1. クラスを使用あなたは、リソースのいくつかの種類を持っている場合は、それらの引数は、その場合には、あなたの関数は、単に使用していることを表して

        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. :ションは、そのクラスの機能をオブジェクトコンストラクタで引数を受け入れ、あなたのversion_*方法作り、変更しています別のクラスを使用して、あなたの関数にオブジェクトパラメータとして提供:

        class Connection(Object): 
            def __init__(self, iserver, ...): 
             self.iserver # etc 
        
        myconn = Connection('iserver',...) 
        
        version_check(myconn) 
        
      3. ほとんどの場合、これらは二つの異なるリソースがあり、2つのクラスでなければなりません。この場合、あなたは、これらのアプローチを組み合わせることができます。

        #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. おそらく、あなたの引数は(例えば、接続および透過プロキシオブジェクト)その場合は、最小の公共でオブジェクトを作成しようとする複数のオブジェクトを表しますversion_*のようなインタフェースメソッドは、オブジェクト構成を使用して他の引数によって表される状態を必要とカプセル化します。例えば

        プロキシ接続を持っている場合、あなただけの転送別のConnectionオブジェクトに、サーバー、ログイン名とパスワード、およびConnectionのすべてのメソッドを持っているConnectionProxy()クラスについて知っているが、Connection()クラスを作成することができます。これにより、proxy*引数を区切ることができ、version_*関数がプロキシを使用しているかどうかを知ることができないことを意味します。

    2. あなたの引数はちょうど状態であり、それらに適切な任意の方法を持っていない場合は、namedtuple()を使用することを検討してください。これはよりスマートなタプル(タプルのアンパック、スライシングなどを含む)のように動作し、既存のコードにはほとんど影響を与えず、使いやすくなります。あなたは多くの引数を持つ関数で終わるとき

      Connection = namedtuple('Connection', 'iserver login password etc') 
      myconn = Connection('iserver', 'loginname', 'passw3rd') 
      version_check(*myconn) 
      
  • 関連する問題