【问题标题】:Python attributes and numpy arraysPython 属性和 numpy 数组
【发布时间】:2013-06-01 05:53:12
【问题描述】:

我有一个存储一些属性的类。这些属性是 numpy 数组,里面有一些浮点数。我希望在创建对象时访问此属性。如果对保存属性值的外部变量执行任何操作,我不希望它们被修改。

使用 getter/setter 或带有其他类型变量的属性很简单,但使用 numpy 数组似乎会失败。

我编写了一个简单的脚本来测试我知道的每一种可能的解决方案。它适用于整数属性,但适用于 numpy 数组。

这是测试类:

class test_class:

    # Initialization
    def __init__(self, attribute1, attribute2, attribute3):

        self.attribute1 = attribute1
        self._attribute2 = attribute2
        self._attribute3 = attribute3

# Attribute 1 with getter and setter
    def get_attr1(self):
        return(self.attribute1)

    def set_attr1(self, value):
        self.attribute1 = value

    # Attribute 2 as a property with getter and setter
    def get_attr2(self):
        return(self._attribute2)

    def set_attr2(self, value):
        self._attribute2 = value

    attribute2 = property(get_attr2, set_attr2)

    # Attribute 3 as a property
    @property
    def attribute3(self):
        return(self._attribute3)

    @attribute3.setter
    def attribute3(self, value):
        self._attribute3 = value

用整数作为属性对其进行测试:

test = test_class(10, 100, 1000)

print test.get_attr1()
print test.attribute2
print test.attribute3

a1 = test.get_attr1()
a2 = test.attribute2
a3 = test.attribute3

a1 += 5
a2 += 50
a3 += 500

print test.get_attr1()
print test.attribute2
print test.attribute3

按预期输出,无需从外部修改属性:

10
100
1000
10
100
1000

用 numpy 数组测试它:

import numpy as np

test = test_class(np.array([10,20,30]), np.array([100,200,300]),   np.array([1000,2000,3000]))

print test.get_attr1()
print test.attribute2
print test.attribute3

a1 = test.get_attr1()
a2 = test.attribute2
a3 = test.attribute3

a1 += 5
a2 += 50
a3 += 500

print test.get_attr1()
print test.attribute2
print test.attribute3

输出不符合预期,值已更改:

[10 20 30]
[100 200 300]
[1000 2000 3000]
[15 25 35]
[150 250 350]
[1500 2500 3500]

那么,如果 getter/setter 和属性都不能与 numpy 数组一起使用,那该怎么办?

编辑:

好吧,我使用copy.deepcopy 函数找到了解决此问题的方法。现在它按预期工作了。

属性定义:

from copy import deepcopy

class test_class:

    ...

    # Attribute 4 with getter and setter using deepcopy
    def get_attr4(self):
        return(deepcopy(self.attribute4))

    def set_attr4(self, value):
        self.attribute4 = value

测试:

test = test_class(np.array([10,20,30]), np.array([100,200,300]), np.array([1000,2000,3000]), np.array([10000,20000,30000]))

...
print test.get_attr4()
...
a4 = test.get_attr4()
...
a4 += 5000
...
print test.get_attr4()

结果:

...
[10000 20000 30000]
...
[10000 20000 30000]

【问题讨论】:

    标签: python properties numpy attributes


    【解决方案1】:

    NumPy 数组是可变的,整数不是。

    >>> a = 1
    >>> id(1)
    4297261152
    >>> a += 1
    >>> id(a)
    4297261184
    

    注意:id 发生变化。

    相对于:

    >>> arr = np.arange(5)
    >>> d(arr)
    4331954736
    >>> arr += 10
    >>> id(arr)
    4331954736
    >>> arr
    array([10, 11, 12, 13, 14])
    

    注意:id 保持不变。

    使用a = test.get_attr1() 或a = test.attribute2 并不重要。你得到的a 是一个 Python 对象,因为几乎所有东西都是你在 Python 中处理的一个对象。一旦你有了a,不管你是如何通过赋值a = 1或作为方法a = test.get_attr1()的返回值来创建它的(该属性只是为方法调用提供了更好的语法。)。那么a 只是一个对象的名称,您可以使用这个对象。如果它像 NumPy 数组一样是可变的,+= 通常会更改内部的值。对于不可变的,这根本不可能。

    如果你不想修改这些对象,你可以复制一份。通常在模块copy 的帮助下。 NumPy 数组提供了自己的复制方法:

    >>> arr2  = arr.copy()
    >>> arr
    array([10, 11, 12, 13, 14])
    >>> arr2 += 100
    >>> arr2
    array([110, 111, 112, 113, 114])
    >>>  arr
    array([10, 11, 12, 13, 14]) 
    

    【讨论】:

    • 我知道对象类型存在差异,在这种情况下是可变的与不可变的。在我的编辑中,您可以看到我使用 copy 库在 getter 方法中提供了 numpy 数组的深层副本,以便返回一个新向量。这样我就可以在不修改属性本身的情况下对数组进行操作。无论如何感谢您的提示,它真的很有价值。
    • 老实说,您的回答对于了解这些类型的对象之间的差异很有价值。但是它并没有解决我的实际问题。我认为有我问题的人会发现我的编辑比你的解释更有趣。不管怎样,我接受了你的。
    • @IñigoHernáezCorres 添加了有关复制的信息。感谢您的提示。
    • 很高兴知道 numpy 数组有一种复制方法。谢谢!
    猜你喜欢
    • 2012-09-11
    • 2021-12-17
    • 2014-06-04
    • 2021-11-24
    • 1970-01-01
    • 2015-03-02
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    相关资源
    最近更新 更多