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

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

そして重要なことの1つは、ほとんどの変数がデータベースから取得されるため、戦略的ではないということです。

4

3 に答える 3

6

def version_check(*args):特に必要な場合を除いて、のような関数を定義することはお勧めしません。ソースを読まずにすばやく:引数はどのような順序になっていますか?proxyServerのデフォルト値をどのように指定しますか?「暗黙的よりも明示的の方が優れている」ことを忘れないでください。

私が日常的にそのルールから逸脱しているのは、次のような別の関数をラップしているときです。

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

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

私はそのような単純な例では決してそれをしませんがfoo、デフォルトやキーワード引数などがたくさんある、私の制御外のサードパーティパッケージの関数であると仮定します。その場合、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データ型を検討してください。これにより、アイテムがキーワードでアドレス指定できるタプルを指定でき、非常にクリーンでエレガントなコードを作成できます。

于 2012-10-11T17:40:57.727 に答える
2

それらの議論が何を表すかに応じて、多くのアプローチがあります。

  1. それらが単なる引数のグラブバッグである場合(特に一部がオプションの場合)、キーワード引数を使用します:

    myargs = {'iserver':'server','login':'username','password':'Pa2230rd'}
    version_get(**myargs)
    
  2. それらが独自の状態で何かを表す場合は、クラスを使用します。

    1. 引数が関数が変更している単一の状態を表す場合は、オブジェクトコンストラクターで引数を受け入れ、version_*メソッドをそのクラスの関数にします。

      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. ある種のリソースがある場合、それらの引数は、関数が単に使用していることを表します。その場合は、別のクラスを使用し、それをオブジェクトパラメーターとして関数に提供します。

      class Connection(Object):
          def __init__(self, iserver, ...):
              self.iserver # etc
      
      myconn = Connection('iserver',...)
      
      version_check(myconn)
      
    3. ほとんどの場合、これらは2つの異なるリソースであり、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()サーバー、ログイン、パスワードだけを知っているConnectionProxy()クラスと、のすべてのメソッドを持っているがConnection別のConnectionオブジェクトに転送するクラスを作成できます。これにより、引数を分離できますproxy*。つまり、version_*関数がプロキシを使用しているかどうかを認識できない可能性があります。

  3. 引数が単なる状態であり、それらに適切なメソッドがない場合は、を使用することを検討してnamedtuple()ください。これは、よりスマートなタプル(タプルのアンパック、スライスなどを含む)のように機能し、既存のコードへの影響を最小限に抑えながら、使いやすくします。

    Connection = namedtuple('Connection', 'iserver login password etc')
    myconn = Connection('iserver', 'loginname', 'passw3rd')
    version_check(*myconn)
    
于 2012-10-11T19:50:19.573 に答える
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
于 2012-10-11T17:31:57.953 に答える