【问题标题】:Updating referenced variables in functions in python更新python函数中的引用变量
【发布时间】:2023-03-27 06:08:01
【问题描述】:

我正在尝试通过类 P 更改矩阵 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]

所以基本上,当控件在B中从p.func2返回到func3时,X应该和self.myX一样。我相信这应该发生,因为 self.myX 默认通过引用传递给 b.func3。

【问题讨论】:

  • 你能澄清一下你得到了什么行为以及你期望什么?正确运行未经修改的代码会为我调用 P 的方法。
  • 您的意思是您希望B.func3() 调用B.func1()B.func2() 而不是P.func1()P.func2()?不清楚你在问什么。
  • 您实际上正在覆盖基类B 中的所有方法,所以我不确定您使用b.B 作为基类的意义。您甚至不需要该基类,因为无论如何您都在p.P.func3 中直接引用b.B.func3。如果您打算保留 b.B 的方法,则需要以不同的方式命名函数。 “未反映在基类 B 中的更改”也令人困惑,因为您实际上只使用基类 B 创建了一个 P 实例。没有B 的实例供您观察任何反射 - 一切都发生在P() 之下。
  • @Idlehands 这是大代码的最低工作版本。我只是想解决这个问题,所以觉得没有必要包含函数的其他细节。

标签: python pass-by-reference


【解决方案1】:

问题出在这里:

#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.myXX 之间的整体对象引用。

之后您可以通过p1.shuffle_order检索订单。

【讨论】:

  • 感谢您的回复。这真的有效!但是,我想保存它们被随机化的顺序以随机播放其他相应的数组。这可能吗?
  • 我已经更新了答案,之后引用了改组的顺序。
猜你喜欢
  • 2023-02-09
  • 2020-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多