Подтвердить что ты не робот

Словарь python, переданный как вход в функцию, действует как глобальная в этой функции, а не локальная

Меня очень смущает поведение ниже. Случаи 1, 3 и 4 выполняются так, как я ожидал, но случай 2 - нет. Почему случай 2 позволяет функции изменять значение словаря в глобальном масштабе, даже если словарь никогда не возвращается функцией? Основная причина, по которой я использую функции, состоит в том, чтобы изолировать все функции от остальной части кода, но это не представляется возможным, если я предпочитаю использовать те же имена переменных внутри функции. Я был в понимании, что все, что явно определено в функции, является локальным для этой функции, но это, похоже, не так, если словарь определен и передан как вход в функцию.. p >

Python 2.7.2+ (default, Oct  4 2011, 20:06:09) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.

============= Случай 1 ===============

>>> def testfun1(a):
...     a=2
... 
>>> a=0
>>> testfun1(a)
>>> a
0

============= Случай 2 ===============

>>> def testfun2(b):
...     b['test']=2
... 
>>> b={}
>>> testfun2(b)
>>> b
{'test': 2}

============= Случай 3 ===============

>>> def testfun3():
...     c=2
... 
>>> c=0
>>> testfun3()
>>> c
0

============= Случай 4 =============== (объясняется этим вопросом: Глобальные словари не нуждаются в ключевом слове global для их изменения?)

>>> def testfun4():
...     d['test']=10
... 
>>> d={}
>>> testfun4()
>>> d
{'test': 10}
4b9b3361

Ответ 1

Передача параметров Python немного отличается от языков, которые вы, вероятно, использовали для. Вместо того, чтобы иметь явный проход по значению и передавать по ссылочной семантике, у python есть проход по имени. Вы, по сути, всегда передаете сам объект, а изменчивость объекта определяет, можно ли его изменить. Списки и дикты являются изменяемыми объектами. Номера, строки и кортежи не являются.

Вы передаете словарь функции, а не копию. Таким образом, когда вы его изменяете, вы также изменяете исходную копию.

Чтобы этого избежать, сначала нужно скопировать словарь перед вызовом функции или из функции (передача этого словаря в функцию dict должна сделать это).

Ответ 2

Глобальное ключевое слово требуется только для назначения (и, вероятно, del, я никогда не пробовал). Мутации объектов вполне допустимы.

Ответ 3

Вы передали объект dict функции и изменили ее внутри функции, поэтому, конечно, она будет изменена после возврата функции. Объект не копируется, поэтому вы изменяете тот же объект, который вы передали, и этот вопрос не имеет ничего общего с именами, похожими именами, областями и т.д., Когда вы явно передали объект.

Ответ 4

Когда вы передаете базовый объект, например целое или строку, в функцию, если вы меняете его внутри функции, ничего не происходит с соответствующим объектом вне функции, потому что когда вы ведете базовый объект, python передает его по значению.

Однако, если вы передаете словарь или список функции, они передаются по ссылке, что означает, что вы будете иметь такое поведение: объект вне функции изменяется, как вы видели.

изменить Кроме того, существует разница между передачей по значению или ссылкой: по значению создается "копия" объекта для использования в функции; по ссылке, точно такой же объект передается через ссылку, а изменения внутри функции видны снаружи. По определению python передает свои неизменяемые объекты по значению и свои изменяемые объекты по ссылке.

Ответ 5

Чтобы поддержать то, что сказал @Casey Kuball, каждый объект в Python передается по ссылке. Каждая функция получает ссылку на фактический объект, который вы передали. Изменение этих объектов зависит от того, являются ли они изменяемыми типами данных.

По сути, можно сказать, что изменяемые объекты, такие как dict, set и list, передаются по ссылке. Неизменяемые объекты, такие как int, str, tuple, передаются по значению.

Не следует также учитывать, что в некоторых случаях изменяемые объекты перезаписываются в функции, теряя при этом ссылку на фактический объект, переданный функции.

>>> def testfun(b):
...     b = b or {}  # Creates a new object if b is false
...     b['test'] = 2
... 
>>> b = {}
>>> testfun(b)
>>> b
{}