#python #pandas #dataframe #pass-by-reference #immutability
#python #pandas #фрейм данных #передача по ссылке #неизменность
Вопрос:
Мой вопрос касается неизменности фрейма данных pandas, когда он передается по ссылке. Рассмотрим следующий код:
import pandas as pd
def foo(df1, df2):
df1['B'] = 1
df1 = df1.join(df2['C'], how='inner')
return()
def main(argv = None):
# Create DataFrames.
df1 = pd.DataFrame(range(0,10,2), columns=['A'])
df2 = pd.DataFrame(range(1,11,2), columns=['C'])
foo(df1, df2) # Pass df1 and df2 by reference.
print df1
return(0)
if __name__ == '__main__':
status = main()
sys.exit(status)
Вывод
A B
0 0 1
1 2 1
2 4 1
3 6 1
4 8 1
и не
A B C
0 0 1 1
1 2 1 3
2 4 1 5
3 6 1 7
4 8 1 9
Фактически, если foo определяется как
def foo(df1, df2):
df1 = df1.join(df2['C'], how='inner')
df1['B'] = 1
return()
(т. Е. Оператор «join» перед другим оператором), тогда вывод просто
A
0 0
1 2
2 4
3 6
4 8
Я заинтригован тем, почему это так. Любые идеи будут оценены.
Комментарии:
1. кстати, return — это не функция, это просто оператор, поэтому вам не нужны скобки после него.
2. Это лучшее обсуждение того, как работают имена Python, о котором я знаю. Как только вы это поймете, вы поймете это поведение.
3. Спасибо @chthonicdaemon !
Ответ №1:
Проблема связана с этой строкой:
df1 = df1.join(df2['C'], how='inner')
df1.join(df2['C'], how='inner')
возвращает новый фрейм данных. После этой строки df1
больше не ссылается на тот же фрейм данных, что и аргумент, а на новый, потому что он был переназначен для нового результата. Первый фрейм данных продолжает существовать без изменений. На самом деле это не проблема pandas, просто общий способ работы python и большинства других языков.
У некоторых функций pandas есть inplace
аргумент, который будет делать то, что вы хотите, однако операция объединения этого не делает. Если вам нужно изменить фрейм данных, вам придется вместо этого вернуть этот новый и переназначить его вне функции.
Комментарии:
1. Спасибо @Jezzamon. Это имеет смысл.
Ответ №2:
В Python нет передачи по значению или передачи по ссылке — есть только привязки имен к объектам.
Если вы измените свою функцию на
def foo(df1, df2):
res = df1.join(df2['C'], how='inner')
res['B'] = 1
return res
Затем df1
df2
, в функции, привязываются к отправленным вами объектам. Результат join
, который в данном случае является новым объектом, привязан к имени res
. Вы можете манипулировать им и возвращать его, не затрагивая какие-либо другие объекты или привязки.
В вашем вызывающем коде вы могли бы просто написать
print foo(df1, df2)