Причина неинтуитивного поведения UnboundLocalError 2 - PullRequest
4 голосов
/ 26 декабря 2010

Вслед за Причина неинтуитивного поведения UnboundLocalError (я предполагаю, что вы его прочитали).Рассмотрим следующий сценарий Python:

def f():
    # a+=1          # 1
    aa=a
    aa+=1

    # b+='b'        # 2
    bb=b
    bb+='b'

    c[0]+='c'       # 3
    c.append('c')
    cc=c
    cc.append('c')

    d['d']=5        # Update 1
    d['dd']=6       # Update 1
    dd=d            # Update 1
    dd['ddd']=7     # Update 1

    e.add('e')      # Update 2
    ee=e            # Update 2
    ee.add('e')     # Update 2

a=1
b='b'
c=['c']
d={'d':4}           # Update 1
e=set(['e'])        # Update 2
f()
print a
print b
print c
print d             # Update 1
print e             # Update 2

Результат сценария:

1
b
['cc', 'c', 'c']
{'dd': 6, 'd': 5, 'ddd': 7}
set(['e'])

Закомментированные строки (отмеченные 1,2) - это строки, которые будут проходить через UnboundLocalError иТАК вопрос, на который я ссылался, объясняет почему.Тем не менее, строка с пометкой 3 работает!

По умолчанию списки копируются по ссылке в Python, поэтому понятно, что c изменяется при изменении cc.Но почему Python должен позволять изменять c в первую очередь, если он не позволяет вносить изменения в a и b непосредственно из области видимости метода?

Я не вижу, как копируется тот факт, что по умолчанию спискиссылка на Python должна сделать это решение о несоответствии.

Что я скучаю по людям?

ОБНОВЛЕНИЯ:

  • Для полноты я такжедобавил словарный эквивалент к вопросу выше, т.е. я добавил исходный код и пометил обновление с помощью # Update
  • . Для дальнейшей полноты я также добавил установленный эквивалент.Поведение сета на самом деле удивительно для меня.Я ожидал, что он будет действовать аналогично списку и словарю ...

Ответы [ 2 ]

3 голосов
/ 26 декабря 2010

В отличие от строк и целых чисел, списки в Python являются изменяемыми объектами.Это означает, что они предназначены для изменения.Строка

c[0] += 'c'

идентична поговорке

c.__setitem__(0, c.__getitem__(0) + 'c')

, которая не вносит никаких изменений в то, с чем связано имя c.До и после этого вызова c - это один и тот же список - изменилось только содержимое этого списка.

Если бы вы сказали

c += ['c']
c = [42]

вфункция f(), то же самое UnboundLocalError произошло бы, потому что вторая строка делает c локальным именем, а первая строка переводит в

c = c + ['c']

, требуя, чтобы имя c былоуже связано с чем-то, что (в этой локальной области) это еще не.

2 голосов
/ 26 декабря 2010

Важно помнить следующее: к какому объекту относится a (или b или c)?Строка a += 1 изменяет, к какому целому относится a.Целые числа являются неизменяемыми, поэтому при изменении от 1 до 2 оно действительно совпадает с a = a + 1, что дает совершенно новое целое число для ссылки.

С другой стороны, c[0] += 'c' не делает 't изменяет, к какому списку относится c, он просто меняет строку, к которой относится его первый элемент.Списки изменчивы, поэтому один и тот же список может быть изменен без изменения его идентичности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...