2013-08-27 3 views
0

Когда я функция, какстранно переменная поведение манипуляции

def foo(A): 
    tmp=A 
    tmp=tmp+1 
    *rest of the function* 
    return 

или

def foo(A): 
    global tmp 
    tmp=A 
    tmp=tmp+1 
    *rest of the function* 
    return 

как на «А» и «TMP» 1 добавляется вместо того, чтобы только «TMP». Что я делаю неправильно и как я могу это исправить?

+0

Я предполагаю, что, основываясь на вопросе о том, что вы попытались упростить код, чтобы сделать ваш вопрос ясным, но в итоге упростил основной вопрос из него. Если вы упростите свой код, чтобы попытаться сделать свой вопрос более кратким, обязательно проверьте его первым! :) –

+0

Я действительно уменьшил проблему достаточно далеко, чтобы я мог безопасно уменьшить код до такого размера, но случайно я путал две версии моего кода. Оба они содержали одну и ту же ошибку, хотя и в другом положении. Комбинация этих двух, как вы правильно сделали, значительно упрощена. К счастью, решение проблемы было дано, несмотря на это. – Erik

+0

Без проблем, рад, что смог в конце концов помочь, несмотря на мою начальную путаницу! –

ответ

0

Как комментарий nneonneo под ответом Блейки (который описывает значительную часть проблемы) утверждает, что код в исходном сообщении не на самом деле делать то, что он утверждает. Например:

def foo(A): 
    tmp = A 
    tmp = tmp + 1 
    return (A, tmp) 

foo(3) 

(3,4) возвращается, означая было оставлено без изменений.

Если это не так, это где A - изменяемый тип. Переменные типы включают в себя списки, словари и производные типы, в то время как целые числа, поплавки и кортежи не изменяются.

Например:

def foo(A): 
    tmp = A 
    tmp[0] = tmp[0] + 1 
    return (A, tmp) 

foo([1, 2]) 

который возвращает ([2, 2], [2, 2]), и в этом случае А изменилось.

Это foo изменяет значение A в случае списка, но не целочисленный случай, потому что списки являются изменяемыми, а целые - нет. Присвоение A tmp, когда A является изменяемым типом, присваивает ссылку на изменяемый объект, а изменение одного из его элементов (как в tmp[0] = tmp[0] + 1) не создает новый объект.

Если вы не хотите, чтобы ваша функция имела подобное поведение в отношении побочных эффектов для списка, например, общая идиома Python заключается в использовании нотации среза для дублирования списка. Это позволит сделать новый список объектов, когда вы назначаете его TMP, который является копией объекта списка в A:

def foo(A): 
    tmp = A[:] 
    # this slice makes a new list, a copy of A 

    tmp[0] = tmp[0] + 1 
    return (A, tmp) 

foo([1, 2]) 

Это возвращает ([1, 2], [2, 2]), так А без изменений и TMP изменяется.

Есть и другие способы копирования списков или других изменяемых объектов, которые тонко отличаются друг от друга. How to clone or copy a list? имеет отличное описание вашего выбора.

-1

Это потому, что параметры метода python передаются по ссылке, а не по значению. Вы существенно изменяете то же место в памяти, что и две разные переменные.

>>> def foo(a): 
    tmp = a 
    print(tmp, a, id(a), id(tmp)) 
>>> foo(5) 
5 5 505910928 505910928 
>>> b = 5 
>>> foo(b) 
5 5 505910928 505910928 
>>> id(b) 
505910928 

И с глобальным Например:

>>> def foo(a): 
    global tmp 
    a = tmp 
    print(a, tmp, id(a), id(tmp)) 
>>> foo(5) 
7 7 505910960 505910960 
>>> foo('s') 
7 7 505910960 505910960 
>>> tmp 
7 
>>> tmp = 6 
>>> foo('a') 
6 6 505910944 505910944 
+0

Да, но 'tmp = tmp + 1' следует переустанавливать' tmp'. – nneonneo

+0

Я не думаю, что его примерный код - это то, что он на самом деле делает. tmp будет отскок, потому что вы даете ему новое целое число, которое будет новым местом в памяти. Если он назначит локальную переменную A глобальной переменной tmp, не имеет значения, что такое A, потому что tmp необходимо явно изменить. Эти осложнения указателя памяти были бы более очевидными, если бы его образец не был целым числом. И, как я уже сказал, я не думаю, что он использовал ints, когда он столкнулся с проблемой (потому что он бы этого никогда не видел) – blakev

+1

Вы предоставили хорошее описание важной части проблемы OP, но я думаю разница между изменяемыми и неизменяемыми типами была еще одной важной базовой концепцией, по которой он, вероятно, отсутствовал. Я отредактировал свой ответ, чтобы удостовериться, что вы предоставили ключевой кусок головоломки. :) –

Смежные вопросы