2015-11-14 2 views
1

Этот код:Функция в python изменяет входные переменные, почему?

def do_something(arg): 
    x=arg 
    x[0] = 9 
    return x 

y = [1,2] 

print "before: ", y 
print "result of do_something(): ", do_something(y) 
print "after: ", y 

Результаты в этом:

before: [1, 2] 
result of do_something(): [9, 2] 
after: [9, 2] 

Я не понимаю, почему функция изменяет первоначальные списки, которые я прохожу? Я даже (попытаюсь) создать новую копию arg (x), чтобы предотвратить ее. Даже если я не верну x, я все равно получаю тот же результат.

+3

Возможный дубликат [ "Наименее Удивления" в Python: Мутабельный аргумент по умолчанию] (http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) или [Как клонировать или копировать список в Python?] (http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python) – styvane

+1

смотреть [факты и Миф о именах и значениях Python] (https://www.youtube.com/watch?v=_AEJHKGk9ns) от Ned Batchelder, и все будет ясно – miraculixx

ответ

1

Поскольку список передается как ссылка на исходный объект. Вам нужно скопировать его в свою функцию или передать ему новый объект списка.
Вы могли бы сделать это так:

def do_something(arg): 
    x=arg[:] 
    x[0] = 9 
    return x 

y = [1,2] 

print "before: ", y 
print "result of do_something(): ", do_something(y) 
print "after: ", y 

Результаты:

before: [1, 2] 
result of do_something(): [9, 2] 
after: [1, 2] 
+0

Я думал, что сделал копию, когда сделал x = arg :) Спасибо за решение! – wessman

1

Все параметры (аргументы) на языке Python передаются по ссылке. Итак, вы передаете ссылку на объект списка. А в функции вы вносите изменения в список. Таким образом, вы видите измененный список после вызова функции.

Чтобы избежать - скопировать список/создать новый, работать с ним и возвращать его в результате выполнения функции.

1
y = [1,2] 

y ----> [1, 2] 

def do_something(arg): 
       ^
        | 
    do_something(y) causes python to do this assignment: arg = y 


y ----> [1, 2] 
     ^
      | 
arg ------+ 

x = arg 

    y ----> [1, 2] 
      ^^ 
       | | 
    arg ------+ | 
       |  
    x -----------+ 

Затем, используя либо x, либо arg, чтобы изменить список приведет к списку, который y видит для изменения. Другими словами, все переменные относятся к одному и тому же списку.

Я даже (попытаюсь) создать новую копию arg (x), чтобы предотвратить ее. Даже если я не возвращаю x, я все равно получаю тот же результат.

Не верно:

def do_something(arg): 
    x = arg[:] 
    x[0] = 9 
    return x 

y = [1,2] 
result = do_something(y) 
print y 
print result 

--output:-- 
[1, 2] 
[9, 2] 
1

Everything is a reference in Python. If you wish to avoid that behavior you would have to create a new copy of the original with list(). If the list contains more references, you'd need to use deepcopy()

Если вы печатаете адрес x и y, вы будете выяснить, что их адреса совпадают, что приводит к результату ,

def do_something(arg): 
    x=arg 
    x[0] = 9 
    print "address of x:", id(x) 
    return x 

y = [1,2] 

do_something(y) 
print "address of y:", id(y) 
Смежные вопросы