Пользовательское транспонирование списка искажает исходную переменную в Python

У меня есть эта функция, которая должна транспонировать полученный список. Это работает, но по какой-то причине изменяет и исходную матрицу: почему?

Matrix = [["1"], ["1","2"], ["1","2","3","4"], []]

def test():
    global Matrix # same happens when global or not
    tMatrix = Matrix
    print(tMatrix) # 1
    tMatrix = transposer(Matrix)
    print(tMatrix) # 2
    print(Matrix) # 3

Выход:

[['1'], ['1', '2'], ['1', '2', '3', '4'], []]   # 1
[['1', '1', '1'], ['2', '2'], ['3'], ['4']]     # 2
[[], [], [], []]                                # 3

Я думаю, это не должно иметь значения, но вот функция транспозитора:

def transposer(m):
    tm = []
    maxi = 0
    for i in range(0, len(m)):
        maxi = max(maxi, len(m[i]))
    for z in range(0, maxi):
        row = []
        for j in range(0, len(m)): 
            try:
                row.append(m[j].pop(0))
            except:
                pass
        tm.append(row)
    return(tm)

Как возможно, что переменная Matrix также затронута, даже если функция не вызывается для этой переменной?


person PascalVKooten    schedule 08.08.2013    source источник


Ответы (1)


Когда вы делаете

tMatrix = Matrix

на самом деле вы делаете tMatrix ссылкой на исходный объект Matrix. Итак, когда вы назначаете вывод функции transposer обратно функции tMatrix, вы действительно изменяете исходный объект Matrix. Это очень распространенное недоразумение, когда вы привыкаете к python, как вы можете увидеть здесь , например (ответ тоже стоит прочитать).

Попробуйте прочитать что-нибудь о том, как Python обрабатывает присваивания, и вы увидите разницу с другими языками:

http://learnpython.pbworks.com/w/page/15956522/Assignment

http://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/variables.html

ИЗМЕНИТЬ:

Чтобы решить эту проблему, вы можете сделать копию исходного объекта, переданного transpose, через копию. операция:

def transposer(n):
    m = copy.copy(n)
    tm = []
    maxi = 0
    for i in range(0, len(m)):
        maxi = max(maxi, len(m[i]))
        print i, maxi
    for z in range(0, maxi):
        row = []
        for j in range(0, len(m)): 
            try:
                row.append(m[j].pop(0))
            except:
                pass
        tm.append(row)
    return(tm)

Как побочное примечание, вы обрабатываете свои элементы как строки. Если они должны были быть числовыми, вы можете просто ввести их без " ". Кроме того, если вам не нужно использовать собственный алгоритм транспонирования, вы можете просто использовать пакет NumPy, который уже выполняет транспонирование матрицы.

person Claudio    schedule 08.08.2013
comment
Может у вас есть решение, что делать вместо этого? Я понимаю, что это ссылка, которую я видел в C++, но там есть возможность сослаться на привязку. - person PascalVKooten; 11.08.2013
comment
Проблема в функции транспонирования. Когда вы делаете m[j].pop(0), вы удаляете элементы из исходного Matrix, который был передан через m. Я редактирую свой ответ, поэтому он делает это правильно. - person Claudio; 12.08.2013
comment
Я нашел этот copy.deepcopy из модуля копирования. Я понятия не имел, что на самом деле хлопки имеют такой побочный эффект! Спасибо. - person PascalVKooten; 12.08.2013