2015-03-08 2 views
0

вот моя проблема. Я хочу создать класс, который со статическим массивом видится для каждого экземпляра моего класса и создан только один раз. Проблема в том, что этот массив не имеет постоянной размерности, но вместо этого он будет создан с заданным размером, например, классом.Экземпляры, указывающие на тот же массив

Вот пример

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)] 

Проблема в том, каждый экземпляр будет иметь копию массива. Я хотел бы создать, скажем, два экземпляра

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

Но массив должен быть создан один раз и храниться где-то в памяти. Когда я укажу другое измерение, он должен создать другой массив, который будет отображаться для тех же экземпляров измерения.

+1

Вы можете сообщить нам, что вы пытаетесь достичь? Или почему вам нужно, чтобы это была переменная класса? – Kedar

+0

этот массив с [1,2,3, ..] был просто примером, указывающим на проблему. В действительности я бы использовал разреженные матрицы из scipy с некоторыми записями (не так просто). У меня есть идея создать два массива классов - один хранит размер уже созданных массивов, а второй - с адресом памяти, где начинается массив. Можно ли установить указатель на эту ячейку памяти, как в C++? –

+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 
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 
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] 
Смежные вопросы