缺少 1 个必需的仅关键字参数

Missing 1 Required Keyword-Only Argument

当我尝试在 Python 3.6 中输入数据帧作为函数参数时,我收到以下函数的错误 'Missing 1 Required Keyword-Only Argument',其中 df 是数据帧,rel_change 是一个数组:

def get_mu(*rel_change, df):

    row_count = len(df.index)
    print("mu count")
    print(row_count)
    mu_sum = 0
    for i in range (0, len(rel_change)):
        mu_sum += rel_change[i]
    mu = (mu_sum) / row_count
    return mu

然后我访问它就像

mu = get_mu(g, df) 

这给出了错误。

我也试过在另一个只计算 row_count 的函数中编写数据帧访问,并将其传递给 mu,但这会产生相同的错误。 我可能做错了什么?

你应该将你的论点翻转为 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 作为消息参数,因为没有给出序列参数。像这样的错误很难追踪,因为代码仍然 运行s 没有引发任何异常。为了完全避免这种可能性,当您想要扩展接受 *args 的函数时,您应该使用 keyword-only 参数(请参阅第 21 条:“使用 Keyword-Only 参数强制清晰”)。

要记住的事情

  • 函数可以通过在 def 语句中使用 *args 来接受可变数量的位置参数。
  • 您可以使用序列中的项目作为带有 * 运算符的函数的位置参数。
  • 将 * 运算符与生成器一起使用可能会导致您的程序 运行 内存不足并崩溃。
  • 向接受 *args 的函数添加新的位置参数会引入 hard-to-find 个错误。

您定义了一个具有可变数量位置参数的函数,*rel_change,它后面只能跟关键字参数。在这种情况下,您必须像这样按名称传递 df

mu = get_mu(g, df=df)

或重新定义 get_mu(),使 df 出现在 *rel_change 之前。