首页 > 解决方案 > DataFrame 作为默认函数参数未按预期工作

问题描述

我很困惑为什么 DataFrame 作为默认函数参数不能像我预期的那样工作。这让我感到困惑,为什么我仍然必须在函数调用中指定它。

基本上我已经创建了一个函数来将数据帧合并到一个主数据帧(我将它设置为默认参数),基于一个键(如左连接)

简化的数据框(只是同一个学生,不同的科目分数):

dfA = pd.DataFrame ({'student': ['A'],
                     'math_score': [50]})

dfB = pd.DataFrame({'student': ['A'],
                    'eng_score': [70]})

dfC = pd.DataFrame({'student': ['A'],
                    'sci_score': [80]})

功能(我想通过将它们合并到主df来一一获取他的科目分数)

def merge_selected(df_to_merge, main_df = dfA):

    # LEFT JOIN to main_df
    main_df = main_df.merge(right=df_to_merge, how='left', on=['student'])

    return main_df

使用函数合并两次:

dfA = merge_selected(dfB)
dfA = merge_selected(dfC)

现在这是我不明白的。我eng_score在第二次合并中输了。不知何故,当我第二次分配dfAmerge_selected,它被删除了。

  student  math_score  sci_score
0       A          50         80

但是如果我main_df = dfA在函数调用中指定:

dfA = merge_selected(dfB, main_df = dfA)
dfA = merge_selected(dfC, main_df = dfA)

我不输eng_score并得到他所有的分数:

  student  math_score  eng_score  sci_score
0       A          50         70         80

基本上我已经解决了这个问题,但希望有人能对此有所了解。

为什么我仍然必须指定main_df,即使它应该默认为dfA

eng_score另外,如果我不指定,为什么我会输main_df = dfA

标签: pythonpython-3.xpandasfunctiondataframe

解决方案


当您使用默认参数 main_df=dfA 定义函数时,该函数会“记住”DataFrame dfA 以供将来所有调用使用。让我们给这个dfA的“原始形式”起一个名字:orig_dfA。

现在,第一次调用merge_selected。您最终使用 orig_dfA 创建了一个新的合并 DataFrame,它存储在内存中的某个位置,与 orig_dfA 不同。

然后,您从函数返回并将 dfA 分配给这个新的合并 DataFrame。事情就是这样。您实际上根本没有更改 orig_dfA 。您只需将名称“dfA”指代这个新的合并 DataFrame,它存储在内存中与 orig_dfA 不同的位置。但是该函数仍然附加到 orig_dfA,它没有改变 - 该函数不知道您希望 main_df 的默认值现在成为“dfA”所指的新 DataFrame!

所以,当涉及到第二个函数调用时,就好像第一个函数从未发生过一样!

这是一个更简单的例子来说明这一点。和以前一样,使用默认值 main_df 定义您的函数。现在,在定义函数之后,立即将 dfA 更改为完全不是 DataFrame 的东西,比如 dfA = 3。现在像​​第一次一样调用你的函数。你会得到完全相同的输出。

这里发生的事情是两件事的混合:

  1. 在 Python 中,赋值 (=) 运算符只是将名称绑定到内存中的对象/值。语句 x = 3 不能作为“留出一些将由名称“x”引用的内存,并将值 3 放在那里”,这是人们可能直觉所期望的。相反,它更像是“在内存中的某处创建值 3 并让名称“x”引用它”。
  2. 当您设置默认参数时,该默认参数引用的对象/值在函数创建时确定并且是固定的。

在您的情况下,在定义转换为“使 main_df 引用 df_A 当前引用的内存中的对象/值”的函数时设置 main_df=df_A 。从这一点开始,您可以让 df_A 引用您喜欢的任何其他内存 - 该函数将始终引用 df_A 在创建函数时引用的同一块内存,而不是 df_A 碰巧引用的任何值函数实际上被调用。


推荐阅读