指向同一数组的实例

时间:2015-03-08 14:51:06

标签: python

这是我的问题。我想创建一个类,其中静态数组对于我的类的每个实例都是可见的,并且只创建一次。问题是这个数组没有常量维度,而是通过类的实例创建给定大小。

这是一个例子

class My(object):
   def __init__(self, N):
      self.a = My.arr(N)

   @classmethod
   def arr(cls, N):
      return [i for i in range(0,N)]

问题是每个Instance都会有一个数组的副本。我想创建两个实例

p1 = My(5)
p2 = My(5)

但是应该创建一次数组并将其存储在内存中。当我指定不同的维度时,它应该创建另一个对于相同维度实例可见的数组。

3 个答案:

答案 0 :(得分:0)

这样的事情可能有用,但我必须说它是一种非常奇特的设计模式:

class My(object):
    _arrays = {}

    def __init__(self, N):
        self._dimension = N
        self._arr(N)

    def _arr(self, N):
        if N not in self._arrays:
            arr = [i for i in range(0,N)]
            self._arrays[N] = arr
        return self._arrays

    @property
    def a(self):
        return self._arrays[self._dimension]

    @a.setter
    def a(self, new):
        if len(new) != self._dimension:
            raise ValueError('Wrong length, should be %d but was %d' %
                             (self._dimension, len(new)))
        self._arrays[self._dimension] = new


if __name__ == '__main__':
    a = My(5)
    b = My(5)
    c = My(10)
    print "# Instances of the same size get the same array:"
    print "a.a and b.a same instance: %r" % (a.a is b.a)
    print "a.a and c.a same instance: %r" % (a.a is c.a)

    a.a[0] = 'five'
    c.a[0] = 'ten'
    print "# Updating the arrays work:"
    print "a array contents: %r" % a.a
    print "b array contents: %r" % b.a
    print "c array contents: %r" % c.a

    a.a = list('abcde')  # new array
    print "# Changing the reference to a new array works:"
    print "a array contents: %r" % a.a
    print "b array contents: %r" % b.a

    print "# Size is protected:"
    a.a = [1, 2, 3]

在此类中,每次创建实例时,都会调用_arr方法。它将在字典_arrays中创建并存储一个正确长度的新数组,该字典是一个类成员。当访问或更改属性a时,将查找当前实例的正确数组。

你也可以设置self.a = self._arrays[self._dimension],但是如果你试图分配一个像a.a = [1, 2, 3]这样的新数组,那么它就不会工作,你也可能最终得到一个错误长度的数组。设定者负责检查。

输出如下:

# Instances of the same size get the same array:
a.a and b.a same instance: True
a.a and c.a same instance: False
# Updating the arrays work:
a array contents: ['five', 1, 2, 3, 4]
b array contents: ['five', 1, 2, 3, 4]
c array contents: ['ten', 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Changing the reference to a new array works:
a array contents: ['a', 'b', 'c', 'd', 'e']
b array contents: ['a', 'b', 'c', 'd', 'e']
# Size is protected:
Traceback (most recent call last):
  File "arrays.py", line 47, in <module>
    a.a = [1, 2, 3]
  File "arrays.py", line 22, in a
    (self._dimension, len(new)))
ValueError: Wrong length, should be 5 but was 3

答案 1 :(得分:0)

这是另一种方法:

#!/usr/bin/env python

class My(object):
    arraystore = {}
    def __init__(self, n):
        if not n in My.arraystore:
            My.arraystore[n] = range(n)
        self.a = My.arraystore[n]

a5 = My(5)
print a5.a, id(a5.a)

a5.a[3] *= 10

b5 = My(5)
print b5.a, id(b5.a)

c = My(7)
print c.a, id(c.a)

典型输出

[0, 1, 2, 3, 4] 3074609804
[0, 1, 2, 30, 4] 3074609804
[0, 1, 2, 3, 4, 5, 6] 3074604812

答案 2 :(得分:0)

你可以这样做:

class My(object):
    a = None  # shared class attribute

    def __init__(self, N):
        My.arr(N)

    @classmethod
    def arr(cls, N):
        if cls.a is None:
            cls.a = list(range(N))
        elif len(cls.a) != N:
            raise ValueError('attempt to change dimension of "a"')

p1 = My(5)
p2 = My(5)
p1.a[0] = 42
print(p1.a)  # --> [42, 1, 2, 3, 4]
print(p2.a)  # --> [42, 1, 2, 3, 4]