我想了解何时应该在python 2.7的函数参数中使用varargs vs列表类型
假设我编写了一个处理URL列表的函数。我可以通过两种不同的方式定义函数:
选项1:
def process_urls(urls):
if not isinstance(urls, list) or isinstance(urls, tuple):
raise TypeError("urls should be a list or tuple type")
选项2:
def process_urls(*urls):
# urls is guaranteed to be a tuple
选项2保证urls
是一个元组,但可以接受随机数量的位置参数,例如process_urls(['url1', 'url2'], "this is not a url")
从编程的角度来看,哪个选项是首选?
答案 0 :(得分:3)
第一个,但没有类型检查。类型检查杀死duck typing。如果调用者想要传递生成器,集合或其他可迭代方法怎么办?不要将它们限制为仅包含列表和元组。
答案 1 :(得分:0)
两个都不是最好的。每种样式在不同情况下都有好处。
在大多数情况下,使用单个可迭代参数会更好,尤其是在调用方已经将URL打包到列表中的情况下。如果他们有一个列表并且需要使用varargs样式,则需要调用process_urls(*existing_list_of_URLs)
,他们会不必要地解压缩然后重新包装参数。正如John Kugelman在他的回答中所建议的那样,您可能不应该使用显式类型检查来强制实参的类型,只是假设它是可迭代的并且可以在此工作。
如果大多数情况下将使用单独的URL调用函数,则使用变量参数列表可能比要求列表更好。例如,URL可能是这样硬编码的:process_urls("http://example.com", "https://stackoverflow.com")
。也许它们在单独的变量中,但是要使用的特定变量直接编码为:process_url(primary_url, backup_url)
。
最后一个选择:支持两种方法!您可以指定函数接受一个或多个参数。如果只有一个,则期望包含URL的可迭代。如果得到多个参数,则期望每个参数都是单独的URL。可能是这样的:
def process_urls(*args):
if len(args) == 1:
args = args[0]
# do stuff with args, which is an iterable of URLs
这有一个缺点,就是将自己传递的单个URL字符串错误地标识为一系列URL,每个URL包含原始字符串中的单个字符。那是一个尴尬的失败案例,因此您可能想要显式检查它。您可以选择引发异常,也可以只接受一个字符串作为参数,就好像它在容器中一样。