简体   繁体   English

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

[英]Best approach to pass and handle arguments to function

After some reading, I found myself struggling with two different approaches to pass a list of arguments to a function. 经过一些阅读,我发现自己正在努力使用两种不同的方法将一个参数列表传递给一个函数。 I read some indications. 我读了一些迹象。 That's what I figured out so far: 这就是我到目前为止所知道的:

Actual code: 实际代码:

file caller.py: file 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)

File: worker.py: 文件: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

And now I have: 现在我有:

file caller.py: 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)

File: worker.py: 文件: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

Using the old approach (actual code) I believe it is more "friendly" to call a function in one line only (as you can see on worker.py). 使用旧方法(实际代码)我认为仅在一行中调用函数更为“友好”(正如您在worker.py上看到的那样)。 But, using the new approach, I think the code get more extensive because for each function I have to define all the same variables. 但是,使用新方法,我认为代码变得更加广泛,因为对于每个函数,我必须定义所有相同的变量。 But is this the best practice? 但这是最好的做法吗? I'm still learning Python on a slow curve, so, sorry for any mistakes in the code. 我仍然在缓慢的曲线上学习Python,所以,对不起代码中的任何错误。

And one important thing, most of the variables are retrieved from a database, so they are not stactic. 还有一件重要的事情是,大多数变量都是从数据库中检索出来的,所以它们并不是一成不变的。

I really don't recommend defining functions like def version_check(*args): unless you specifically need to. 我真的不建议定义def version_check(*args):等函数def version_check(*args):除非你特别需要 Quick, without reading the source: what order are the arguments in? 快速,无需阅读来源:参数的顺序是什么? How do you specify a default value for proxyServer? 如何为proxyServer指定默认值? Remember, "explicit is better than implicit". 请记住,“明确胜过隐性”。

The one time I routinely deviate from that rule is when I'm wrapping another function like: 有一次我经常偏离这个规则是当我包装另一个函数时:

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

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

I'd never do it for such a simple example, but suppose foo is a function from a 3rd-party package outside my control with lots of defaults, keyword arguments, etc. In that case, I'd rather punt the argument parsing to Python than attempt it myself. 我从来没有为这样一个简单的例子做过,但是假设foo是一个来自我控制之外的第三方包的函数,有很多默认值,关键字参数等等。在这种情况下,我宁愿将参数解析为Python比自己尝试。

Personally, I'd write that as a class like: 就个人而言,我会把它写成一个类:

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

And then in the client, write: 然后在客户端写下:

from worker import Worker

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

If you really need to write functions with lots of arguments instead of encapsulating that state in a class - which is a more typically Pythonic way to do it - then consider the namedtuple datatype from recent Python versions. 如果你真的需要编写带有大量参数的函数而不是在类中封装该状态 - 这是一种更典型的Pythonic方法 - 那么请考虑最近Python版本的namedtuple数据类型。 It lets you specify a tuple where items are addressable by keyword and can make for some very clean, elegant code. 它允许您指定一个元组,其中的项目可以通过关键字进行寻址,并且可以生成一些非常干净,优雅的代码。

There are many approaches, depending on what those arguments represent. 有许多方法,取决于这些参数代表什么。

  1. If they are just a grab-bag of arguments (especially if some are optional), use keyword arguments : 如果它们只是一个参数包(特别是如果有些是可选的),请使用关键字参数

     myargs = {'iserver':'server','login':'username','password':'Pa2230rd'} version_get(**myargs) 
  2. If they represent some thing with its own state, then use classes : 如果它们用自己的状态表示某些东西,那么使用

    1. If the arguments represent a single state that your functions are modifying, then accept the arguments in the object constructor and make your version_* methods functions of that class: 如果参数表示您的函数正在修改的单个状态,则接受对象构造函数中的参数并生成该类的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. If you have some kind of resource those arguments represent that your functions are merely using, in that case use a separate class, and supply it as an object parameter to your functions: 如果您有某种资源,那些参数表示您的函数仅仅使用,在这种情况下使用单独的类,并将其作为对象参数提供给您的函数:

       class Connection(Object): def __init__(self, iserver, ...): self.iserver # etc myconn = Connection('iserver',...) version_check(myconn) 
    3. Most likely, these are two different resources and should be two classes. 最有可能的是,这些是两种不同的资源,应该是两类。 In this case you can combine these approaches: 在这种情况下,您可以组合这些方法:

       #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. Possibly, your arguments represent more than one object (eg, a connection and a transparent proxy object) In that case, try to create an object with the smallest public interface methods like version_* would need and encapsulate the state represented by the other arguments using object composition. 可能,您的参数代表多个对象(例如,连接和透明代理对象)在这种情况下,尝试使用像version_*所需的最小公共接口方法创建一个对象,并使用其他参数封装其他参数所表示的状态对象组成。

      For example, if you have proxy connections, you can create a Connection() class which just knows about server, login and password, and a ConnectionProxy() class which has all the methods of a Connection , but forwards to another Connection object. 例如,如果您有代理连接,则可以创建一个Connection()类,它只知道服务器,登录名和密码,以及一个ConnectionProxy()类,它具有Connection所有方法,但转发到另一个Connection对象。 This allows you to separate the proxy* arguments, and means that your version_* functions can be ignorant of whether they're using a proxy or not. 这允许您分离proxy*参数,这意味着您的version_*函数可能不知道他们是否正在使用代理。

  3. If your arguments are just state and don't have any methods proper to them, consider using a namedtuple() . 如果您的参数只是状态并且没有适合它们的任何方法,请考虑使用namedtuple() This will act like a smarter tuple (including tuple unpacking, slicing, etc) and have minimal impact on your existing code while still being easier to use. 这将像一个更聪明的元组(包括元组解包,切片等),对现有代码的影响最小,同时仍然更容易使用。

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

You can create instance an object or define a class. 您可以创建实例对象或定义类。 eg 例如

file caller.py: file 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)

file worker.py: 文件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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM