传递和处理函数参数的最佳方法

时间:2012-10-11 17:13:37

标签: python pep8

经过一些阅读,我发现自己正在努力使用两种不同的方法将一个参数列表传递给一个函数。我读了一些迹象。这就是我到目前为止所知道的:

实际代码:

文件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上看到的那样)。但是,使用新方法,我认为代码变得更加广泛,因为对于每个函数,我必须定义所有相同的变量。但这是最好的做法吗?我仍然在缓慢的曲线上学习Python,所以,对于代码中的任何错误都很抱歉。

还有一件重要的事情,大多数变量都是从数据库中检索出来的,因此它们不是策略性的。

3 个答案:

答案 0 :(得分:6)

我真的不建议定义像def version_check(*args):这样的功能,除非您特别需要。快速,无需阅读来源:参数的顺序是什么?如何为proxyServer指定默认值?请记住,“明确比隐含更好”。

有一次我经常偏离那个规则就是当我包装另一个函数时:

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

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

我从来没有为这样一个简单的例子做过,但假设foo是一个来自我控制之外的第三方软件包的函数,有许多默认值,关键字参数等。在这种情况下,我' d而不是解析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()

如果你真的需要编写带有大量参数的函数而不是在类中封装该状态 - 这是一种更典型的Pythonic方法 - 那么请考虑最近Python版本的namedtuple数据类型。它允许您指定一个元组,其中的项目可以通过关键字进行寻址,并且可以创建一些非常干净,优雅的代码。

答案 1 :(得分: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. 最有可能的是,这是两种不同的资源,应该是两个类。在这种情况下,您可以结合使用这些方法:

      #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()类,它具有{{1的所有方法转发到另一个Connection对象。这允许您分隔Connection参数,这意味着您的proxy*函数可能不知道他们是否使用代理。

  3. 如果您的参数只是状态且没有适合的方法,请考虑使用namedtuple()。这将像一个更聪明的元组(包括元组解包,切片等),对现有代码的影响最小,同时仍然更容易使用。

    version_*

答案 2 :(得分:0)

您可以创建实例对象或定义类。 e.g。

文件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