你应该把你的论点改成get_mu(df, *rel_change)。不要忘记翻转函数调用:get_mu(df, g)。可选的位置参数(通常称为星形参数,参考参数的常规名称 *args)需要放在关键字参数之后。
要了解更多细节,我强烈推荐 Brett Slatkin 的《Effective Python: 59 Specific Ways to Write Better Python》一书。以下是休息后关于该主题的摘录:
第 18 项:使用可变位置参数减少视觉噪音
接受可选的位置参数(通常称为星形参数,参考参数的常规名称 *args)可以使函数调用更清晰并消除视觉噪音。
例如,假设您想记录一些调试信息。使用固定数量的参数,您将需要一个接收消息和值列表的函数。
def log(message, values):
if not values:
print(message)
else:
values_str = ', '.join(str(x) for x in values)
print('%s: %s' % (message, values_str))
log('My numbers are', [1, 2])
log('Hi there', [])
>>>
My numbers are: 1, 2
你好
当您没有要记录的值时,必须传递一个空列表既麻烦又嘈杂。最好完全省略第二个参数。您可以在 Python 中通过在最后一个位置参数名称前加上 * 来执行此操作。日志消息的第一个参数是必需的,而任何数量的后续位置参数都是可选的。函数体不需要改变,只有调用者做。
def log(message, *values): # The only difference
if not values:
print(message)
else:
values_str = ', '.join(str(x) for x in values)
print('%s: %s' % (message, values_str))
log('My numbers are', 1, 2)
log('Hi there') # Much better
>>>
My numbers are: 1, 2
Hi there
如果你已经有一个列表并且想要调用一个变量参数函数,比如 log,你可以使用 * 操作符来做到这一点。这指示 Python 将序列中的项目作为位置参数传递。
favorites = [7, 33, 99]
log('Favorite colors', *favorites)
>>>
Favorite colors: 7, 33, 99
接受可变数量的位置参数有两个问题。
第一个问题是变量参数在传递给你的函数之前总是变成一个元组。这意味着如果您的函数的调用者在生成器上使用 * 运算符,它将被迭代直到它用尽。生成的元组将包含生成器中的每个值,这可能会消耗大量内存并导致程序崩溃。
def my_generator():
for i in range(10):
yield i
def my_func(*args):
print(args)
it = my_generator()
my_func(*it)
>>>
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
接受 *args 的函数最适合您知道参数列表中的输入数量相当少的情况。它非常适合将许多文字或变量名一起传递的函数调用。主要是为了程序员的方便和代码的可读性。
*args 的第二个问题是,如果不迁移每个调用者,将来就无法向函数添加新的位置参数。如果您尝试在参数列表的前面添加位置参数,如果不更新现有调用者,它们将会巧妙地中断。
def log(sequence, message, *values):
if not values:
print('%s: %s' % (sequence, message))
else:
values_str = ', '.join(str(x) for x in values)
print('%s: %s: %s' % (sequence, message, values_str))
log(1, 'Favorites', 7, 33) # New usage is OK
log('Favorite numbers', 7, 33) # Old usage breaks
>>>
1: Favorites: 7, 33
Favorite numbers: 7: 33
这里的问题是第二次调用 log 使用 7 作为消息参数,因为没有给出序列参数。像这样的错误很难追踪,因为代码仍然可以运行而不会引发任何异常。为了完全避免这种可能性,当你想扩展接受 *args 的函数时,你应该使用仅关键字参数(参见第 21 条:“使用仅关键字参数强制清晰”)。
要记住的事情
- 函数可以通过在 def 语句中使用 *args 来接受可变数量的位置参数。
- 您可以将序列中的项目用作带有 * 运算符的函数的位置参数。
- 将 * 运算符与生成器一起使用可能会导致程序内存不足并崩溃。
- 向接受 *args 的函数添加新的位置参数可能会引入难以发现的错误。