Python——仅在变量存在时传递参数
Posted
技术标签:
【中文标题】Python——仅在变量存在时传递参数【英文标题】:Python -- Only pass arguments if the variable exists 【发布时间】:2013-05-10 16:53:48 【问题描述】:我有以下变量,用户可以选择通过表单提交(它们不是必需的,但可以这样做以过滤搜索)。
color = request.GET.get ('color')
size = request.GET.get ('size')
现在我想将这些变量传递给一个函数,但前提是它们存在。如果它们不存在,我只想运行不带参数的函数。
没有参数的函数是:
apicall = search ()
只有颜色
apicall = search (color)
它的颜色和大小是
apicall = search (color, size)
如果定义了参数,我想将它传递给函数,但如果不是,我不想传递它。
最有效的方法是什么? python 有内置的方法吗?
【问题讨论】:
【参考方案1】:在 python 3 中,您可以将它们打包到一个列表中,对其进行过滤,然后使用 *
-operator 将列表解压缩为 search
的参数:
color = request.GET.get ('color')
size = request.GET.get ('size')
args = [ arg for arg in [color, size] if arg ]
search(*args)
但是请注意,如果color
是假的,而size
是真的,那么您将调用search
,其中一个参数是size
的值,这可能是错误的,但原始问题没有在这种情况下不要提及期望的行为。
(死灵,因为我一直在寻找比我更好的解决方案,但发现了这个问题)
【讨论】:
【参考方案2】:尽管我很喜欢@HenryKeiter 的solution,Python 提供了一种更简单的方法来检查参数。事实上,有几种不同的解决方案。
-
例如,如果
search()
是一个独立的函数并且您想查看参数,您可以使用inspect 模块,如this solution 所示。
示例代码 1
>>> import inspect
>>> print(inspect.getfullargspec(search))
ArgSpec(args=['size', 'color'], varargs=None, keywords=None, defaults=(None, None))
-
但是,如果
search()
是一个类的方法(我们称之为Search
),那么您可以简单地使用内置的vars 函数来查看所有类方法及其参数:
示例代码 2
>>> import Search
>>> print(vars(Search))
mappingproxy('__init__': <function Search.__init__(self, size, color)>,
'search': <function Search.search(self, size, color))
第二种方法的唯一警告是,它作为一种视觉检查工具而不是一种程序化工具更有用,尽管从技术上讲你可以说if 'size' in vars(Search)['search']: do something
。它只是不会很健壮。说if 'size' in inspect.getfullargspec(Search.search).args: do something
或for arg in inspect.getfullargsspec(Search.search).args: do something
更容易和更持久
【讨论】:
【参考方案3】:假设这是一个标准的get
调用(就像在字典上一样),这应该很容易。使用None
定义您的函数作为参数的默认值,然后传递color
和size
而无需检查它们!
def apicall(color=None, size=None):
pass # Do stuff
color = request.GET.get('color')
size = request.GET.get('size')
apicall(color, size)
这样,您只需在一个地方检查None
参数(在函数调用内部,无论如何您都必须检查该函数是否可以通过多种方式调用)。一切都保持良好和干净。当然,这假设(就像我在顶部所说的那样)您的 get
调用就像普通 Python 字典的 get
方法,如果找不到该值,则返回 None
。
最后,我注意到您的函数名称是apicall
:您实际上可能无法访问函数代码本身。在这种情况下,由于您可能对函数签名的默认值一无所知并且None
可能是错误的,因此我可能会编写一个简单的包装器来为您进行参数检查。然后就可以像上面那样调用包装器了!
def wrapped_apicall(color=None, size=None):
if color is None and size is None:
return apicall()
# At least one argument is not None, so...
if size is None:
# color is not None
return apicall(color)
if color is None:
# size is not None
return apicall(size)
# Neither argument is None
return apicall(color, size)
注意:第二个版本不应该是必要的,除非你看不到你正在调用的代码并且没有任何文档!使用None
作为默认参数是很常见的,因此您很可能只使用第一种方式。如果你不能修改你正在调用的函数并且你不知道它的默认参数是什么(或者它的默认参数是模块常量或其他东西,但这种情况很少见),我只会使用包装器方法。
【讨论】:
是的,但是如果我没有定义其中一个变量,那么apicall (color, size)
会抛出一个错误,不是吗?
好的,谢谢...你写的是我假设的方式,但我认为必须有更有效的方法...
@user1328021 假设这两行都执行:color = request.GET.get('color')
和size = request.GET.get('size')
,那么color
和size
都保证被定义,尽管它们可能是None
。您认为这方面效率低下的地方是什么?
我猜这个解决方案可以使用装饰器和参数字典推广到任意数量的变量,但不确定如何。这对于防止部分赋值覆盖函数参数(使用 functools.partial 指定)很有用
第二个代码 sn-p 中的 if color is None
块可能应该被省略,除非你坚持从字面上理解 OP。如果 API 同时接受颜色和大小作为其唯一参数,那将是糟糕的设计。从给出的例子来看,search(size)
不应该是一个选项。【参考方案4】:
在定义方法时,如果设置了默认参数,则可以指定或不指定参数。
def search(color=None, size=None):
pass
然后,当您调用它时,您可以根据自己的选择指定关键字参数。这两个都是有效的:
apicall = search(color=color)
apicall = search(size=size)
【讨论】:
以上是关于Python——仅在变量存在时传递参数的主要内容,如果未能解决你的问题,请参考以下文章