Форум русскоязычного сообщества Ubuntu


Увидели сообщение с непонятной ссылкой, спам, непристойность или оскорбление?
Воспользуйтесь ссылкой «Сообщить модератору» рядом с сообщением!

Автор Тема: Python 3. Вопрос по работе интерпретатора.  (Прочитано 692 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн VVP_vic

  • Автор темы
  • Новичок
  • *
  • Сообщений: 2
    • Просмотр профиля
Моя задача на примитивном примере:
Исходный список: a=['a','b','c','d']
Нужно получить:a=[['X','b','c','d'],['a','X','c','d'],['a','b','X','d'],['a','b','c','X']]
т.е. последовательно менять один из элементов исходного списка на 'X' и добавлять каждый полученный список в исходный.
# coding: utf-8
a=[['a','b','c','d']]
b=['a','b','c','d']
for i in range(0,len(b)):
    c=b
    c[i]='X'
    a.append(c)
print(a)
print(b)
полученный результат:
[['a', 'b', 'c', 'd'], ['X', 'X', 'X', 'X'], ['X', 'X', 'X', 'X'], ['X', 'X', 'X', 'X'], ['X', 'X', 'X', 'X']]
['X', 'X', 'X', 'X']
Он показывает, что интерпретатор даже список b поменял который вне пределов цикла, потому что видимо с=b, и все четыре новых списка он тоже приравнял к последнему с неправильному, т.к. он постепенно менял и b.
На числовых значениях такого не происходит. Т.е. он не меняет значение b, если я к нему приравняю с, а потом с изменю, b не поменяется.
Вопрос: как мне обойти эту особенность интерпретатора, если он меняет даже то, что вроде менять не должен?

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Python 3. Вопрос по работе интерпретатора.
« Ответ #1 : 04 Января 2016, 20:31:32 »
В питоне списки это исключительно ссылочная структура - т.е. с=b это просто получить в переменную с еще одну ссылку на то, на что ссылается b. т.е. у вас всего один список (b он же с) в программе изменяется.

Копировать список нужно явно: с = b[:] или c = b.copy()

Кроме того, у вас первый элемент не такой как по заданию. Нужно а присваивать пустой список в начале.

« Последнее редактирование: 04 Января 2016, 23:26:06 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Azure

  • Модератор раздела
  • Старожил
  • *
  • Сообщений: 6017
  • Windows10, i3wm on Debian9, Manjaro20.0
    • Просмотр профиля
Re: Python 3. Вопрос по работе интерпретатора.
« Ответ #2 : 04 Января 2016, 21:41:47 »
Как на меня генератором списка проще
Код: (python) [Выделить]
template = ['a', 'b', 'c', 'd']
result = [template[:i]+['X']+template[i+1:] for i in range(len(template))]
или
Код: (python) [Выделить]
lt = len(template)
result = [['X' if i==j else template[i] for i in range(lt)] for j in range(lt)]
« Последнее редактирование: 05 Января 2016, 13:20:37 от Azure »
В Линукс можно сделать ВСЁ что угодно, достаточно знать КАК !

shura1

  • Гость
Re: Python 3. Вопрос по работе интерпретатора.
« Ответ #3 : 04 Января 2016, 22:17:24 »
Кто сказал, что в Питоне нет tmwtdi)))

Так, в порядке бреда :) - Python3:

from functools import reduce
a = ['a', 'b', 'c', 'd']
reduce(lambda x, y: x.append(a[:]) or x[-1].__setitem__(y, 'X') or x, range(len(a)), [])

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Python 3. Вопрос по работе интерпретатора.
« Ответ #4 : 04 Января 2016, 23:29:52 »
Jshura, вы уже вовсе какой-то хакерский код привели, у Azure, хоть понятно что и как...

Azure, да ошибся - поправил.


Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

shura1

  • Гость
Re: Python 3. Вопрос по работе интерпретатора.
« Ответ #5 : 05 Января 2016, 07:04:18 »
Sly_tom_cat,
Я ж и говорю в порядке бреда))) Зато работает)

===

Для ТС - можно сказать, что в Питоне нет переменных - есть имена и значения. (В стандартном Python tutorial из документации термин variable не употребляется).

Когда вы пишете b=a, вы даете имя "b" значению, которое уже имеет имя "a". Результатом являтся то, что одно значение имеет два имени.

Есть разница при присваивании имен неизменяемым (immutable) и изменяемым (mutable) значениям. Числа, строки, кортежи (tuples) неизменяемы. Поэтому при

a = "hello"
b = a

неважно, ссылаются ли имена a и b на одинаковые строки или разные. Вышеуказанный код семантически равнозначен следующему
a = "hello"
b = "hello"


Совсем другое дело, когда значения изменяемы (mutable). Из стандартных типов данных Питона это списки, словари, множества. При
a = [1,2,3]
b = a

дается два разных имени одному и тому же значению. Поэтому, когда вы меняете значение, пользуясь именем "а", вы, естественно, можете наблюдать эти изменения и пользуясь именем "b"

a[0] = 100
print(b[0]) # ==> 100

Что бы имя "b" содержало копию значения, на которое ссылается имя "а" - надо (не поверите) скопировать значение. Общий способ такой:

from copy import copy
b = copy(a)

Для списков существует более краткий путь - b = a[:]
« Последнее редактирование: 05 Января 2016, 10:03:16 от Jshura »

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Python 3. Вопрос по работе интерпретатора.
« Ответ #6 : 05 Января 2016, 11:22:35 »
К сказанному Jshura, добавлю.

Когда вы работаете с immutable то каждое присвоение это создание нового экземпляра данных.
Так, если вы предварительно присвоите

a=5

а потом присвоите

a=a+1

то фактически в памяти создается:
- при присвоении a=5: экземпляр класса int со значением 5
- при присвоении a=a+1: новый экземпляр класса int со значением 6
При этом во втором присвоении на экземпляр класс int со значением 5(старое значение а) теряется ссылка от а. Если при этом на это значение никто больше не ссылался, то экземпляр становится мусором, который позже (когда интерпритирору потребуется память, будет утилизирован (преобразован в свободную память) сборщиком мусора.

При этом, если вы напишите

a="hello"
b=a

То на экземпляр строки "hello" будут ссылаться две переменных, но как только вы напишите присвоение (например)

b = b[:-1]

То будет создан новый экземпляр строки "hell" и уже на него будет ссылаться b.
Даже если вы захотите в строке поменять один символ, интрепритатор создаст новый экземпляр строки, например

b.replace('o', 'a')

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

Но, в отличии от первого примера с цифрами - в примере со строками мусор не появляется, т.к. на экземпляр строки "hello" у нас продолжает ссылаться a.
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн VVP_vic

  • Автор темы
  • Новичок
  • *
  • Сообщений: 2
    • Просмотр профиля
Re: Python 3. Вопрос по работе интерпретатора.
« Ответ #7 : 12 Января 2016, 22:09:28 »
Спасибо всем огромное! Разобрался в происходящих процессах и понял где ошибался!

 

Страница сгенерирована за 0.063 секунд. Запросов: 25.