Вопрос:
Прежде всего, я понимаю, что я могу использовать оператор global для доступа к глобальным переменным. Но каким-то образом мне удалось изменить глобальный список без global, как показано ниже:
def func1(nums): nums = [4,5,6] nums = [1,2,3] func1(nums) print nums # print [1,2,3] def func2(nums): nums[0] = 4 nums[1] = 5 nums[2] = 6 nums = [1,2,3] func2(nums) print nums # print [4,5,6]
После попытки func2 я понял, что всегда могу получить доступ к глобальному списку в функции, если я укажу индекс:
def func3(nums): nums[:] = [4,5,6] nums = [1,2,3] func3(nums) print nums # print [4,5,6]
Это потому, что Python автоматически пытается сопоставить глобальную переменную, если перед определением используется функциональная переменная?
Спасибо.
Ответ №1
Я понимаю, что я могу использовать глобальную инструкцию для доступа к глобальным переменным
Ваше понимание неверно. Вы всегда можете получить доступ к глобальной переменной, если у вас нет локальной переменной с тем же именем. Вам понадобится только оператор global, когда вы собираетесь изменить объект, на который ссылается имя переменной. В вашем func2 вы этого не делаете; вы изменяете только содержимое объекта. nums по-прежнему относится к тому же списку.
Ответ №2
Это концепция, основанная на изменяемых и неизменяемых объектах в Python. В вашем случае, например:
a=[1,2] def myfn(): a=[3,4] print id(a) >>>id(a) 3065250924L >>>myfn() 3055359596
Ясно, что оба являются разными объектами. Сейчас:
a=[1,2] def myfn(): a[:] =[3,4] print id(a) >>>id(a) 3055358572 >>>myfn() 3055358572
Это означает, что это одна и та же переменная, используемая в локальной и глобальной области.
Ответ №3
В этом конкретном случае это происходит потому, что list являются изменяемыми.
В результате их использование в глобальном пространстве имен или даже передача через функцию означает, что они будут изменены, поскольку Python содержит ссылку на изменяемый объект, а не его копию.
Если вы попытаетесь сделать то же самое с tuple, это не сработает, поскольку они неизменяемы.
Способ избежать этого – предоставить копию списка функции, а не самому списку:
func2(list[:])
В то же время вы можете сделать это с помощью аргументов по умолчанию, где вы можете указать аргумент по умолчанию как [], и если вы тогда .append() что-то к нему, этот аргумент по умолчанию навсегда удерживает этот элемент внутри него для все будущие вызовы (если вы не удалите их каким-либо образом).
Ответ №4
- 2 переменные nums различаются, и они указывают на один и тот же объект или на два разных объекта, хотя они имеют одинаковое имя.
- когда вы вызываете func1(nums), означает, что вы передаете ссылку. Теперь 2 переменная nums указывает на тот же объект. (2 переменные, 1 объект)
- когда вы назначаете в func1, внутренняя переменная nums будет указывать на новый объект, внешний объект остается неизменным (2 переменные, 2 объекта)
- и когда вы вызываете print nums, тогда nums является внешней переменной,
Ответ №5
Есть два фактора для этого результата:
- Переменные – это просто имена, которые ссылаются на объекты
- Список изменчив
В func1, nums относится к новому объекту, потому что новый список будет создан. Поэтому global nums не затрагиваются.
В func2 модификация применяется к переданному объекту. Таким образом, global nums изменяются. Новый объект не создан, потому что list изменчив.