Обновление ссылочных переменных в функциях в Python - PullRequest
0 голосов
/ 15 ноября 2018

Я пытаюсь изменить порядок матрицы X через класс P, который уже передан функции в базовом классе B. Изменение порядка не отражается в базовом классе B. Есть ли способ достичь этого? Пожалуйста, смотрите следующее MWE:

#p.py
import numpy as np
import b

class P(b.B):

    def __init__(self, opts):
        self.opts = opts

    def func1(self, X):

        print('func1:',X)

    def func2(self):

        randomize = np.arange(len(self.myX))
        np.random.shuffle(randomize)
        self.myX = self.myX[randomize]

        print('func2',self.myX)

    def func3(self, X):
        """
        X is a 2d matrix 
        """
        self.myX = X
        #call the function from the base class 
        b.B.func3(self, self.myX)  

#b.py
class B:
    """
    base class.

    """
    def __init__(self, opts):
        self.opts = opts


    def func3(self, X):

        for n in range(2):
            for i in range(X.shape[0]):
                self.func1(X[i])
            self.func2()

с консоли:

p1 = p.P({})
X=np.array([[1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7], [6,7,8]])
p1.func3(X)

Токовый выход:

func1: [1 2 3]
func1: [2 3 4]
func1: [3 4 5]
func1: [4 5 6]
func1: [5 6 7]
func1: [6 7 8]
func2 [[6 7 8]
 [3 4 5]
 [2 3 4]
 [5 6 7]
 [4 5 6]
 [1 2 3]]
func1: [1 2 3]
func1: [2 3 4]
func1: [3 4 5]
func1: [4 5 6]
func1: [5 6 7]
func1: [6 7 8]

Ожидаемый результат:

func1: [1 2 3]
func1: [2 3 4]
func1: [3 4 5]
func1: [4 5 6]
func1: [5 6 7]
func1: [6 7 8]
func2 [[6 7 8]
 [3 4 5]
 [2 3 4]
 [5 6 7]
 [4 5 6]
 [1 2 3]]
func1: [6 7 8]
func1: [3 4 5]
func1: [2 3 4]
func1: [5 6 7]
func1: [4 5 6]
func1: [1 2 3]

Таким образом, в основном, когда элемент управления возвращается из p.func2 в func3 в B, X должен совпадать с self.myX. Я считаю, что это должно произойти, потому что self.myX по умолчанию передается по ссылке на b.func3.

1 Ответ

0 голосов
/ 15 ноября 2018

Проблема здесь:

#class p.P
    def func2(self):

        randomize = np.arange(len(self.myX))
        np.random.shuffle(randomize)
        self.myX = self.myX[randomize]  # <-- this line

        print('func2',self.myX)

Вы фактически переназначили self.myX на новый рандомизированный массив np, изменив ссылку на объект с X на этот новый рандомизированный массив.

Если вы добавили print(id(self.myX)) между этой строкой, вы заметите, что начальные контрольные точки вернулись к X, но после переназначения его id уже не тот.

Вы должны сделать это вместо того, чтобы поддерживать ссылку:

np.random.shuffle(self.myX)

Если вы действительно хотите перетасовать также внутренний массив:

for arr in self.myX:
    np.random.shuffle(arr)
np.random.shuffle(self.myX)

Это также будет поддерживать ссылку.

Редактировать: Если вы хотите сохранить ссылку на рандомизированный порядок при сохранении объекта, это немного сложнее, но выполнимо:

# use make randomize an instance attribute so you can refer to it even after the function ended
self.shuffle_order = np.arange(len(self.myX))
np.random.shuffle(self.shuffle_order)

# loop through each inner array and reassign based on a copy of the shuffled matrix
for i, arr in enumerate(self.myX[self.shuffle_order]):
    self.myX[i] = arr

Это изменяет внутренний массив, но поддерживает общую ссылку на объект между self.myX и X.

После этого вы можете получить заказ через p1.shuffle_order.

...