2012-10-11 82 views
5

经过一番阅读后,我发现自己正在努力用两种不同的方法将参数列表传递给函数。我读了一些迹象。这就是我想通了,至今:传递和处理函数参数的最佳方法

实际代码:

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

现在我有:

file 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,所以,对于代码中的任何错误感到抱歉。

而且一件重要的事情是,大部分变量都是从数据库中检索出来的,所以它们并不稳定。

+5

一般来说,当你结束了与许多参数的函数,你需要考虑你的设计更多一些。传递一个对象比那么多参数要好? –

+0

@MartijnPieters有可能给我一个例子吗?同时我会尝试在s.o上找到它。和python文档。 –

+1

这组参数代表什么?可以命名吗?如果是这样,使它成为一个名为tuple或自定义类来保存该信息,那么你有一个对象来传递,而不是x个单独的参数。 –

回答

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() 

如果你真的需要有很多的参数写入功能,而不是把这个状态封装在一个类中 - 这是一种更典型的Pythonic方法 - 然后考虑最近的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'来代替。无论如何,这个approuch并不比使用关键字参数更好,参见[@Francis'答案中的项目1](http://stackoverflow.com/a/12847386/4279) – jfs

2

有很多方法,取决于这些参数代表什么。

  1. 如果他们只是参数(尤其是如果有些是可选择的)一个抓斗袋,使用关键字参数

    myargs = {'iserver':'server','login':'username','password':'Pa2230rd'} 
    version_get(**myargs) 
    
  2. 如果他们代表了自己的状态的一些事情,然后使用

    1. 如果参数代表一个国家,你的FUNC蒸发散正在修改,然后接受在对象构造函数中的参数,使您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()类,它只是知道服务器,登录名和密码,并且具有Connection的所有方法ConnectionProxy()类,但转发到另一个Connection对象。这使您可以分开参数proxy*,这意味着您的功能可能不知道他们是否使用代理服务器。

  3. 如果你的论点是只是状态,没有适当的给他们的任何方法,可以考虑使用namedtuple()。这将像一个更聪明的元组(包括元组拆包,切片等),并且对现有代码的影响最小,同时仍然更易于使用。

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