Append продолжает добавлять один и тот же элемент, не добавляет правильные, Python

Это то, что я импортировал:

import random
import matplotlib.pyplot as plt
from math import log, e, ceil, floor
import numpy as np
from numpy import arange,array
import pdb
from random import randint

Здесь я определяю матрицу функций (p, m)

def matrix(p,m):            # A matrix with zeros everywhere, except in every entry in the middle of the row
    v = [0]*m
    v[(m+1)/2 - 1] = 1
    vv = array([v,]*p)
    return vv

ct = np.zeros(5)            # Here, I choose 5 cause I wanted to work with an example, but should be p in general  

Здесь я определяю MHops, который в основном берет размеры матрицы, матрицы и вектора ct и дает мне новую матрицу mm и новый вектор ct

def MHops(p,m,mm,ct):

k = 0
while k < p :                 # This 'spans' the rows
    i = 0
    while i < m :             # This 'spans' the columns
        if mm[k][i] == 0 :
            i+=1
        else:
            R = random.random()
            t = -log(1-R,e)              # Calculate time of the hopping
            ct[k] =  ct[k] + t
            r = random.random()
            if  0 <= r < 0.5 :              # particle hops right
                if 0 <= i < m-1:
                    mm[k][i] = 0
                    mm[k][i+1] = 1
                    break
                else: 
                    break           # Because it is at the boundary
            else:                            # particle hops left 
                if 0 < i <=m-1:    
                    mm[k][i] = 0
                    mm[k][i-1] = 1
                    break
                else:              # Because it is at the boundary
                    break
            break
    k+=1    
return (mm,ct)               # Gives me the new matrix showing the new position of the particles and a new vector of times, showing the times taken by each particle to hop

Теперь то, что я хочу сделать, это повторить этот процесс, но я хочу иметь возможность визуализировать каждый шаг в списке. Вкратце, что я делаю: 1. создаю матрицу, представляющую решетку, где 0 означает, что в этом слоте нет частицы, а 1 означает, что там есть частица. 2. Создайте функцию MHops, которая имитирует случайное блуждание в один шаг и дает мне новую матрицу и вектор ct, который показывает время движения частиц.

Теперь я хочу иметь вектор или массив, в котором у меня есть 2 * n объектов, то есть матрица mm и вектор ct для n итераций. Мне нужен массив, список или что-то в этом роде, потому что мне нужно использовать их позже.

Здесь начинается моя проблема:

Я создаю пустой список и использую append для добавления элементов на каждой итерации цикла while. Однако результат, который я получаю, представляет собой список d с n равными объектами, полученными из последней итерации!

Следовательно, моя функция для итерации следующая:

def rep_MHops(n,p,m,mm,ct):
    mat = mm
    cct = ct
    d = []
    i = 0
    while i < n :
        y = MHops(p,m,mat,cct)       # Calculate the hop, so y is a tuple y = (mm,ct)
        mat = y[0]                 # I reset mat and cct so that for the next iteration, I go further
        cct = y[1]
        d.append(mat)
        d.append(cct)
        i+=1
    return d


z = rep_MHops(3,5,5,matrix(5,5),ct)      #If you check this, it doesn't work
print z

Однако это не работает, я не понимаю, почему. Что я делаю, так это использую MHops, затем я хочу установить новую матрицу и новый вектор как те, что на выходе MHops, и сделать это снова. Однако, если вы запустите этот код, вы увидите, что v работает, т.е. вектор времени увеличивается и матрица решетки изменяется, однако, когда я добавляю это к d, d в основном представляет собой список из n равных объектов, где объект являются последней итерацией.

В чем моя ошибка? Кроме того, если у вас есть какие-либо советы по кодированию для этого кода, они будут более чем кстати, я не уверен, что это эффективный способ.

Просто чтобы вы лучше поняли, я хотел бы использовать окончательный вектор d в другой функции, где прежде всего я выбираю случайное время T, затем я в основном проверяю каждую нечетную запись (каждый ct) и, следовательно, проверяю каждую запись каждого ct и посмотрим, меньше ли эти числа или равны Т. Если это произошло, то движение частицы произошло, иначе - нет. Затем я попытаюсь визуализировать с помощью matpotlibt результат с помощью гистограммы или чего-то подобного.

Есть ли кто-нибудь, кто знает, как запустить такое моделирование в Matlab? Как вы думаете, было бы легче?


person Euler_Salter    schedule 10.06.2016    source источник
comment
Я не уверен в логике, потому что не знаком с проблемой, но у меня есть несколько советов для вашего кода. списки могут быть добавлены с помощью метода .append(object_to_append), как показано ниже. В некоторых случаях полезно заменить элементы в списке list[index] = some_value, однако в вашем случае нет смысла создавать список с n индексами. просто создайте пустой список и используйте метод добавления на каждой итерации, а не заменяйте предварительно созданное значение!   -  person TheLazyScripter    schedule 10.06.2016
comment
Спасибо за ваш комментарий, однако я уже пробовал это. Раньше у меня был d = [], а после cct = y[1] у меня были d.append(mat) и d.append(cct), но это не сработало!!   -  person Euler_Salter    schedule 10.06.2016
comment
У меня было: def rep_MHops(n,p,m,mm,ct): mat = mm cct = ct d = [] `i = 0` while i < n : y = MHops(p,m,mat,cct) `mat = y[0]` cct = y[1] d.append(mat) d.append(cct) `i+=1` `return d`   -  person Euler_Salter    schedule 10.06.2016
comment
Вы передаете список (фактически двухуровневый массив) в MHops, который изменяет его и возвращает. По сути, это ссылка. Таким образом, вы получаете 5 копий одной и той же ссылки в своем выходном списке. Вариант stackoverflow .com/questions/1132941/.   -  person Corley Brigman    schedule 10.06.2016
comment
Спасибо, Корли Бригман. Я просмотрел вопрос, который вы предложили мне прочитать, однако я не понимаю, как они связаны. Парень в вопросе каждый раз получает разные ответы, а я всегда получаю одно и то же. Как мне изменить свой код, чтобы он работал и получил желаемый список d? А что такое ссылка?   -  person Euler_Salter    schedule 10.06.2016
comment
@CorleyBrigman прав. Вы передаете и сохраняете ссылки, а не копии, поэтому на следующей итерации вашего цикла MHops изменяет вашу ранее сохраненную версию в d. Вместо этого используйте import copy; d.append(copy.deepcopy(mat)), чтобы сохранить копию, которая не будет изменена позже.   -  person RedCraig    schedule 10.06.2016
comment
@CorleyBrigman О, хорошо, я понимаю, поэтому на протяжении цикла while в определении я просто изменяю его и даю ему новое имя, поэтому, когда я добавляю его в список d, я как будто добавляю одно и то же «имя» n раз. Но тогда как я должен добавить эти результаты в список?   -  person Euler_Salter    schedule 10.06.2016
comment
@RedCraig, это работает, большое спасибо! Как я могу проголосовать за ваш комментарий?   -  person Euler_Salter    schedule 10.06.2016


Ответы (1)


Вы передаете и сохраняете ссылки, а не копии, поэтому на следующей итерации вашего цикла MHops изменяет вашу ранее сохраненную версию в d. Вместо этого используйте import copy; d.append(copy.deepcopy(mat)), чтобы сохранить копию, которая не будет изменена позже.

Почему?

Python передает список по ссылке, и в каждом цикле вы сохраняете ссылку на один и тот же матричный объект в d.

Я просмотрел документы по python, и единственное упоминание, которое я могу найти, это "как написать функцию с выходными параметрами (вызов по ссылке)".

Вот более простой пример вашего кода:

def rep_MHops(mat_init):
    mat = mat_init
    d = []
    for i in range(5):
        mat = MHops(mat)
        d.append(mat)
    return d


def MHops(mat):
    mat[0] += 1
    return mat

mat_init = [10]
z = rep_MHops(mat_init)
print(z)

При запуске выдает:

[[15], [15], [15], [15], [15]]

Python передает только изменяемые объекты (например, списки) по ссылке. Целое число не является изменяемым объектом, вот слегка измененная версия приведенного выше примера, которая работает с одним целым числом:

def rep_MHops_simple(mat_init):
    mat = mat_init
    d = []
    for i in range(5):
        mat = MHops_simple(mat)
        d.append(mat)
    return d


def MHops_simple(mat):
    mat += 1
    return mat

z = rep_MHops_simple(mat_init=10)
print(z)

При запуске выдает:

[11, 12, 13, 14, 15]

это поведение, которое вы ожидали.

Этот ответ SO Как передать переменную по ссылке? очень хорошо объясняет это.

person RedCraig    schedule 10.06.2016
comment
Большое спасибо @RedCraig! Я на самом деле никогда не думал об этом - person Euler_Salter; 13.06.2016