Уведомления

Группа в Telegram: @pythonsu

#1 Апрель 3, 2017 00:01:59

Bilbo
Зарегистрирован: 2017-03-23
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Помогите разобраться в ошибке

Есть такая программа:

 win_row = [(0,1,2),
           (3,4,5),
           (6,7,8),
           (0,3,6),
           (1,4,7),
           (2,5,8),
           (0,4,8),
           (2,4,6)]
MOVES = [4,0,2,7]
for i in win_row:
    for j in MOVES:
        if j in i:
            print ("\n", j, "-", i, "id of i -", id(i), "id of element -", id(win_row[win_row.index(i)]), win_row)
            win_row.remove(i)
Не понимаю, почему появляется ошибка. Удаляю элемент, но переменная, которая на него ссылалась не обнуляется. В чем подвох?

Отредактировано Bilbo (Апрель 3, 2017 00:20:35)

Офлайн

#2 Апрель 3, 2017 01:31:45

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9999
Репутация: +  857  -
Профиль   Отправить e-mail  

Помогите разобраться в ошибке

Нельзя менять список, который перебираешь (в общем случае). Чтобы это исправить, перебирай копию.

Bilbo
 for i in win_row:
 for i in win_row[:]:

И у копии будут другие id(), но это и не важно, потому что само использование id() вызывает вопросы.



Отредактировано py.user.next (Апрель 3, 2017 01:33:54)

Офлайн

#3 Апрель 3, 2017 11:17:57

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Помогите разобраться в ошибке

Bilbo
Удаляю элемент, но переменная, которая на него ссылалась не обнуляется.
А с чего она должна обнуляться?
вот у вас написано
 if j in i:
            win_row.remove(i)
допустим перрвое же сравнение выдаст True, вы радостно удаляете i, что оно будет дальше удалять? нужно превать цикл, после удаления…
Дальше удалили вы первый элемент списка,на его место станет следующий, индексы всех элемнтов сдвинулись, первый стал нулевым, второй первым и т.д. как вы думаете какой элемент for возьмет следующим? нулевой он взял, следовательно возьмет первый, но первый уже имеет индекс 0, тоесть по факту он возьмет второй элемент из “изначального” списка, а первый у вас вообще проигнориться…
Вобщемто py.user.next говорит правильно, нельзя менять список который перебираешь, но если очнь хочеться или нужно, лабораторная там или задание где нжно решить задачу именно таким путем, то for тут использовать нельзя, нужно использвать while
 win_row = [(0,1,2),
           (3,4,5),
           (6,7,8),
           (0,3,6),
           (1,4,7),
           (2,5,8),
           (0,4,8),
           (2,4,6),
           ]
MOVES = [4,0,2,7]
i=0                                                 #начальный индекс
while i < len(win_row):                    # пока i менше длинны списка
    for j in MOVES:               
        if j in win_row[i]:                       #если в элемнте списка есть число из MOVES
            win_row.remove(win_row[i])  # удалить элемент
            break                                   # прервать цикл
    else:                                       # если цикл завершился без  break 
        i+= 1                                  # увеличиваем индекс на 1
print(win_row)



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Апрель 3, 2017 17:06:03)

Офлайн

#4 Апрель 3, 2017 15:59:18

Bilbo
Зарегистрирован: 2017-03-23
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Помогите разобраться в ошибке

PEHDOM
допустим перрвое же сравнение выдаст True, вы радостно удаляете i, с чем будет оно дальше сравнивать? нужно превать цикл, после удаления…
Проблема в том, что внутри списка удаляется кортеж, на этот кортеж ссылается переменная i. По моему разумению после удаление кортежа, i должна выдавать None. Но вместо этого i не обнуляется, элементы списка j продолжают искаться в i, хотя самого i уже существовать не должно.

 for j in MOVES:
        if j in i:
            win_row.remove(i)

Представляю это так:
Ищем 4 в (0,1,2)
Ищем 0 в (0,1,2)
0 найдена в (0,1,2)
удаляем (0,1,2)
*Ищем 2 в (0,1,2)
2 найдена в (0,1,2)
пытаемся удалить (0,1,2)
ОШИБКА: (0,1,2) на найдена в списке

Мне кажется, что после (*) должно выглядеть так:
*Ищем 7 в None

далее интерпретатор переходит на следующий кортеж - (3,4,5).

Т. е. почему после удаления (0,1,2) переменная i не принимает значение None? Хочу понять, что принимает i. Получается, что i ссылается на другой участок памяти в отличие от win_row (где k - это порядковый номер элемента равный i). Получается, что i = win_row, либо i = (0,1,2). И здесь мы имеем второй вариант?

Отредактировано Bilbo (Апрель 3, 2017 16:27:48)

Офлайн

#5 Апрель 3, 2017 17:03:02

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Помогите разобраться в ошибке

Bilbo
Проблема в том, что внутри списка удаляется кортеж, на этот кортеж ссылается переменная i. По моему разумению после удаление кортежа, i должна выдавать None.
Скуяли? i ссылаеться на кортеж, и win_row 0,например, ссылаеться на тот же кортеж.Данные остаються в памяти пока на них ссылается хотябы одна переменная. В данном случае на него ссылеться i и он будет в памяти до конца итерации for. После того как i примет следующее значение, сборщик мусора “увидит” что на кортеж больше нет ни одной ссылки и освободит память занимаемую кортежем.

То что вы удалили кортеж из списка, означает что вы удалили ссылку на кортеж из списка, а не кортеж из памяти. Это никак не обнуляет i на None.
Bilbo
Хочу понять, что принимает i. Получается, что i ссылается на другой участок памяти в отличие от win_row (где k - это порядковый номер элемента равный i). Получается, что i = win_row, либо i = (0,1,2). И здесь мы имеем второй вариант?
i = (0,1,2) даже если вы удалите этот кортеж из списка кортеж остеться в памяти пока на него указывает хотябы одна переменная. i будет указывать на этот кортеж пока ее не переназначат или не удалят.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Апрель 3, 2017 17:38:50)

Офлайн

#6 Апрель 3, 2017 21:38:14

Bilbo
Зарегистрирован: 2017-03-23
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Помогите разобраться в ошибке

Спасибо, PEHDOM. Я запутался. Мне почему-то казалось, что удалив кортеж, он именно удалится. Читал Доусона, там есть раздел “распределенные ссылки”. Пример такой:

i = [1,2,3]
j = i
k = i
del j[0]
print (k)
>>> [2,3]
По аналогии мне показалось, что должно работать также в вышеобозначенном случае. Но теперь запутался как это работает.

Отредактировано Bilbo (Апрель 3, 2017 21:38:35)

Офлайн

#7 Апрель 3, 2017 22:53:33

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

Помогите разобраться в ошибке

Bilbo
Мне почему-то казалось, что удалив кортеж, он именно удалится.
Нет, он удалиться только из списка, если на него указвает еще какаянибудь переменная он останеться в памяти.
Python имеет автоматическое управление памятью: подсчёт ссылок для большинства объектов и сборка мусора для удаления циклов. Память освобождается сразу после того, как была удалена последняя ссылка на объект.
https://ru.wikibooks.org/wiki/Python/%D0%A3%D1%87%D0%B5%D0%B1%D0%BD%D0%B8%D0%BA_Python_3.1
в догонку для болшего понимания
Все объекты делятся на ссылочные и атомарные. К атомарным относятся int, long (в версии 3 любое число int, так как в версии 3 нет ограничения на размер), complex и некоторые другие. При присваивании атомарных объектов копируется их значение, в то время как для ссылочных копируется только указатель на объект, таким образом, обе переменные после присваивания используют одно и то же значение. Ссылочные объекты бывают изменяемые и неизменяемые….



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Апрель 3, 2017 23:05:32)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version