Python类成员在不赋值的情况下更改值



我有一个类"测试";其中我声明了两个实例,并在其上称为";"更新";功能"测试;是一个numpy数组。

b1 = test()
b1.randomize(2, 0, 0, 0, 0, 0)
b2 = test()
b2.randomize(6, 0, 0.5, 0, 0, 0)
print(b1.a)
print(b2.a)
update(b1,b2)
print(b1.a)
print(b2.a)

更新功能定义如下。问题是b2.a的值在调用update后发生了变化,尽管从未在其中分配它。我也从来没有做过像";b2.a=b1.a";,这将改变b2.a的引用。下面还复制了类定义。

def update(b1, b2):
dx = b1.p[0,0] - b2.p[0,0]
dy = b1.p[0,1] - b2.p[0,1]
b1.a[0,0] += (-dx) * b2.m
b1.a[0,1] += (-dy) * b2.m
class test:
m = 1.0
r = 0.1
p = np.zeros((1,2))
v = np.zeros((1,2))
a = np.zeros((1,2))
def randomize(self, m_mean, m_stddev, pos_mean, pos_stddev, v_mean, v_stddev):
self.m = np.random.normal(loc = m_mean, scale = m_stddev)
self.p = np.random.normal(loc = pos_mean, scale = pos_stddev, size = (1,2))
self.v = np.random.normal(loc = v_mean, scale = v_stddev, size = (1,2))

a是一个类变量,因此它由所有实例共享。如果您想要一个对每个实例都唯一的a变量,则需要在类中添加以下内容:

def __init__(self):
self.a = np.zeros((1,2))

您使用的实例属性不正确。当您在类之后在python中定义变量时,这在同一对象的不同实例之间是常见的,因此如果其中一个实例更改属性的值对于其他实例,此值也将更改。

您需要做的是在实例化对象时定义值,这通常是在__init__方法内部完成的像这样:

class Test:
def __init__(self):
self.m = 1.0
self.r = 0.1

例如检查https://realpython.com/lessons/class-and-instance-attributes/了解更多信息。

我看到了几个问题。

  • 缺少init
  • 不使用self初始化(n,m,p,r,v,a(

在以上基础上进行扩展,您还应该避免直接访问类变量。为您提供了一个getter和setter函数的小示例,您可以使用它们来访问类的私有变量。

class test:
@property
def m(self):
return self._m
@m.setter
def m(self, value):
self._m = value
def __init__(self):
self._m = 1.0
self._r = 0.1
self._p = np.zeros((1,2))
self._v = np.zeros((1,2))
self._a = np.zeros((1,2))
def randomize(self, m_mean, m_stddev, pos_mean, pos_stddev, v_mean, v_stddev):
self._m = np.random.normal(loc = m_mean, scale = m_stddev)
self._p = np.random.normal(loc = pos_mean, scale = pos_stddev, size = (1,2))
self._v = np.random.normal(loc = v_mean, scale = v_stddev, size = (1,2))

这里的问题是a是一个类变量,因此在b1和b2之间共享。

尽管如果将新对象分配给b1.a(类似于b1.a = np.ones((1, 2))(,这不会是一个问题,因为这将为实例b1声明一个新的实例变量a,而b2.a仍然引用对象。所以b1.a会改变,但是b2.a不会。确切地说,b1.ab2.a现在是指两个不同的对象。

>>> b1, b2 = test(), test()
>>> print("b1.a = {}, b2.a = {}".format(b1.a, b2.a)) 
b1.a = [[0. 0.]], b2.a = [[0. 0.]]
>>> b1.a = np.ones((1, 2))
>>> print("b1.a = {}, b2.a = {}".format(b1.a, b2.a)) 
b1.a = [[1. 1.]], b2.a = [[0. 0.]]

但是,当您执行b1.a[0, 0] = (-dx) * b2.m时,您正在更改a作为引用的容器内的值。由于该容器由b1.a和b2.a共享,因此在这种情况下,b1.ab2.a都发生了更改,因为它们仍然指向相同的对象(或容器(。

>>> b1, b2 = test(), test()
>>>> print("b1.a = {}, b2.a = {}".format(b1.a, b2.a))
b1.a = [[0. 0.]], b2.a = [[0. 0.]]
>>> b1.a[0, 0] = 100  # 
>>> print("b1.a = {}, b2.a = {}".format(b1.a, b2.a)) 
b1.a = [[100.   0.]], b2.a = [[100.   0.]]

最新更新