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

时间:2018-02-15 19:28:30

标签: python pandas csv dataframe keyword

当我尝试在Python 3.6中输入数据帧作为函数参数时,我收到错误'缺少1个必需的关键字参数'对于以下函数,其中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,但这会产生相同的错误。 我能做错什么?

2 个答案:

答案 0 :(得分:2)

你应该将你的论点翻转为get_mu(df, *rel_change)。不要忘记翻转函数调用:get_mu(df, g)。可选的位置参数(通常称为参数的传统名称的星形参数,* args)需要在关键字参数之后。

有关更多详细信息,我强烈推荐Brett Slatkin撰写的“有效的Python:编写更好的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的函数添加新的位置参数会引入难以发现的错误。

答案 1 :(得分:2)

您已经定义了一个具有可变数量的位置参数NotificationCenter.default.addObserver( self, selector: #selector(self.didHideEditMenu), name: NSNotification.Name.UIMenuControllerDidHideMenu, object: nil) NotificationCenter.default.addObserver( self, selector: #selector(self.willHideEditMenu), name: NSNotification.Name.UIMenuControllerWillHideMenu, object: nil) 的函数,该函数只能跟随关键字参数。在这种情况下,您必须按名称传递*rel_change

df

或重新定义mu = get_mu(g, df=df) ,以便在get_mu()之前显示df