LINUX.ORG.RU

Работа со списками в Питоне

 


0

1

Если запустить такой скрипт:

mx = 5
my = 5
m = [([0] * mx)] * my
for x in range(mx):
    for y in range(my):
        m[x][y] = ((x%2 == 0)and(y%2==0))
for l in m:
    print(l)

Вместо ожидаемого (False в нечётных строках или колонках):
[True, False, True, False, True]
[False, False, False, False, False]
[True, False, True, False, True]
[False, False, False, False, False]
[True, False, True, False, True]
получается (False только в нечётных колонках):
[True, False, True, False, True]
[True, False, True, False, True]
[True, False, True, False, True]
[True, False, True, False, True]
[True, False, True, False, True]
Почему так происходит?

Ответ: Применение * к списку умножает не список, а ссылку на список. Реально в m — 5 ссылок на одну строку.

★★★★★

Последнее исправление: question4 (всего исправлений: 1)

Потому что у тебя не 5 разных строк, а пять ссылок на одну строку. По этому ты везде получаешь то что получил в последней строке

gnunixon ★★★
()
Ответ на: комментарий от gnunixon

Ради эксперимента, можешь теперь поменять последний элемент последней строки и распечатать матрицу, и увидеть что во всех строках последний элемент будет таким же

gnunixon ★★★
()
Последнее исправление: gnunixon (всего исправлений: 1)

Да уж, и правда интересные грабли..

Создавай вот так:

mx = 5                                                                          
my = 5                                                                          
m = [[0 for x in range(mx)] for y in range(my)]                                 
for x in range(mx):                                                             
    for y in range(my):                                                         
        m[x][y] = ((x%2 == 0)and(y%2==0))                                       
for l in m:                                                                     
    print(l)
Crocodoom ★★★★★
()
Ответ на: комментарий от gnunixon

Спасибо!

А как тогда инициализировать вложенный список? Или какой тип данных лучше взять?

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

А как тогда инициализировать вложенный список?

массивы в питоне!=массивы в Си

питон динамический язык

(можно не инициализировать если че) кодом с многомерными массивами никто не пользуется «также как в Си»

missxu
()

BTW, если сразу писать с привлечением list comprehensions, то потребность в начальном нулевом массиве отпадает вовсе:

mx, my = 5, 5
m = [[x%2 == 0 and y%2 == 0 for x in range(mx)] for y in range(my)]
for l in m:
    print(l)
Crocodoom ★★★★★
()
Последнее исправление: Crocodoom (всего исправлений: 1)
Ответ на: комментарий от Crocodoom

если сразу писать с привлечением list comprehensions, то потребность в начальном нулевом массиве отпадает вовсе

По плану большая часть массива — нули, а условия для ненулевых более сложные. %2 я сделал чтобы упростить до предела при поиске ошибки.

Можно ли как-то вставить в это выражение if-then-elif-elif-else? Или не стоит?

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

В list comprehension можно использовать только выражения, а if-elif-elif-else это не выражение.

Но ты можешь использовать тернарный оператор вида T if COND else F, а также фильтры вида if COND. Вот, для примера:

>>> [('neg' if x < 0 else 'pos') for x in range(-10, 10) if x % 2 == 0]
['neg', 'neg', 'neg', 'neg', 'neg', 'pos', 'pos', 'pos', 'pos', 'pos']

условия для ненулевых более сложные

Попробуй вынести их в отдельные функции

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

T if COND else F

Воистину уродский синтаксис. Что заставило разработчиков языка разнести операнды-результата по разные стороны от условного выражения?

SiberianHusky
()
Ответ на: комментарий от SiberianHusky

Что заставило разработчиков языка разнести операнды-результата по разные стороны от условного выражения?

Гвидо, конечно же

Crocodoom ★★★★★
()
Ответ на: комментарий от missxu

массивы в питоне!=массивы в Си

Как раз приведённый пример вполне соответствует внутреннему устройству Си :) когда делается массив ссылок на 1-мерные массивы.

question4 ★★★★★
() автор топика
>>> import numpy as np
>>> m = np.zeros((5,5))
>>> m[::2,::2] = 1
>>> m
array([[1., 0., 1., 0., 1.],
       [0., 0., 0., 0., 0.],
       [1., 0., 1., 0., 1.],
       [0., 0., 0., 0., 0.],
       [1., 0., 1., 0., 1.]])
>>> print(*m.astype(bool), sep='\n')
[ True False  True False  True]
[False False False False False]
[ True False  True False  True]
[False False False False False]
[ True False  True False  True]

:)

anonymous
()
Ответ на: комментарий от question4

По плану большая часть массива — нули

А не эффективнее будет использовать вместо матрицы set только тех точек, которые True?

E ★★★
()
Ответ на: комментарий от E

А не эффективнее будет использовать вместо матрицы set только тех точек, которые True?

Так или иначе, матрицу надо будет выводить на экран. Многократно. Либо тупо перерисовывать всю, либо каждый раз проверять каждую точку на вхождение в сет. Что быстрее?

Кроме того, всё это — черновик. В окончательном варианте попробую всё — и простую матрицу, и разреженную (или какой правильный термин?), и генерацию на лету.

question4 ★★★★★
() автор топика
Ответ на: комментарий от aedeph_

Справочник по языку — более 600 килобайт текста. По библиотекам ­— 10 с половиной мегабайт. Держать всё это в голове не получается.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Ага, why waste time learning, when ignorance is instantaneous?

Python Tutorial в очень вдумчивом режиме читается за день. И даже его после не надо держать в голове, только индексы.

aedeph_ ★★
()

Вообще, если нужно много и сложно работать с многомерными массивами в python - советую обратить внимание на всякие numpy с pandas-ами. Быстрее и экономнее будет, и даже код короче выйдет. В общем случае обычно если ты что-то делаешь с многомерными массивом в цикле, значит ты делаешь что-то не так. Да, пандас под капотом тоже циклы устроит, но зато быстрее и оптимальнее

gnunixon ★★★
()
Последнее исправление: gnunixon (всего исправлений: 1)
Ответ на: комментарий от gnunixon

numpy с pandas

Глянул уже numpy, тем более у меня матричное умножение вылезло :) Который из них быстрее преобразует матрицу в набор стрингов для curses?

question4 ★★★★★
() автор топика
Ответ на: комментарий от aedeph_

Где в Python Tutorial рассматривается эта ошибка?

Да, она в документации есть, но совсем в другом месте. Я её нашёл уже после того, как объяснили.

А Tutorial я проходил с выполнением упражнений. В марте. Большую часть уже забыл.

question4 ★★★★★
() автор топика
Ответ на: комментарий от gnunixon

В общем случае обычно если ты что-то делаешь с многомерными массивом в цикле, значит ты делаешь что-то не так.

Согласен. Поэтому и применил для заполнения m оператор * С вышеописанным результатом :)

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Там просто не рассматриваются метод __rmul__ для списков, а для декартовых произведений и наколеночных многомерных массивов предлагается использовать вложенные list comprehension'ы, что и вызвало бы отсутствие этой ошибки

То есть ты же где-то узнал про то, что __rmul__ можно использовать, но прочитать про него поленился. Результаты в шапке.

aedeph_ ★★
()
Ответ на: комментарий от aedeph_

Я уже сказал: после быстрго прочтения 11 мегабайт в голове остаётся очень мало.

А почему тебя это так возбуило?

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Поэтому никто никогда и не читает быстро 11 мегабайт.

Меня это не слишком возмущает, просто вызывает удивления, что пятизвёздочный не в состоянии загуглить и прочитать доку или разжёвывание для самых маленьких на so.

aedeph_ ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.