2015-07-21 6 views
2

Я исхожу из фона Matlab. В Matlab я могу создать определение класса, а затем создать массив объектов. Я могу легко разыменовать каждый объект с помощью индекса. Кроме того, когда я вызываю метод из массива объектов (без индекса), у меня есть доступ ко всем объектам массива. Например, скажем, что myNewClass имеет свойства .data и .text, он также имеет метод .clob. Я могу:Как создать собственный класс коллекции в Python

% init 
a(1) = myNewClass; 
a(2) = myNewClass; 

a(1).data = [0;0;0]; 
a(2).data = [1;1;1]; 

Так что теперь, если я называю a.clob (а не (1) .clob или .clob (2)), я могу сделать что-то вроде

% this is a function inside the methods definition of my class definition 
function clob(self) 
    % self here is my object array, "a", from above 
    for i=1:length(self) 
     % deref a single object 
     self(i).goClobYourself; 
    end 
end 

Как я делаю что-то подобное в Python? Обратите внимание: я хочу, чтобы мой класс был индексированной коллекцией, вроде списка. Но я не хочу, чтобы мой «класс-список» принимал любой класс, только myNewClass. Если я наследую «список», мой класс будет просто «списком» с атрибутами .data, .text и функцией .clob? Также обратите внимание: я не хочу «список», содержащий мои объекты, я хочу, чтобы мои объекты были перечислены, чтобы я мог их отделить от индекса: a [1] .clob() или (1) .clob () (?? или что-то типа того). Или я хочу передать весь массив себе: a.clob() дает мне доступ к списку. У меня может быть немного облачной терминологии.

С наилучшими пожеланиями

+0

«Но я не хочу мой «класс-список», чтобы принять любой класс, просто myNewClass ». Простой ответ: «Не делай этого». Практически никогда не было веских оснований для этого. Это может быть обычным явлением в MATLAB, но на Python он сильно нахмурился. – TheBlackCat

ответ

1

Всех таких возможностей в Python использовать «специальные имена методов», как описаны в справочном разделе 3.3 Языка. В разделе 3.3.6 описывается, как эмулировать типы контейнеров, что в целом является тем, о чем вы просите здесь. Вам необходимо определить и внедрить методы __getitem__, __setitem__, __delitem__ и, возможно, также __iter__, __reversed__ и __contains__. Python неплохо подходит для этого, и этот подход очень гибкий.

0

При программировании на Python выполнение проверок типов не является невероятно распространенным явлением. Вы уверены, что вам нужен ваш список, чтобы принимать только один тип (и его подтипы), или вы доверяете программисту читать ваши документы и не ставить что-то в этом не должно быть?

Если да, то вот пример общий класс, который наследует от collections.MutableSequence, что, вероятно, что вы хотите:

from collections import MutableSequence 
class VerifierList(MutableSequence): 
    _list = None 
    def __init__(self, allowedClasses, *args, **kwargs): 
     super(VerifierList, self).__init__() 
     self._list = list(*args, **kwargs) 
     self.allowedClasses = tuple(allowedClasses) 
    def __repr__(self): 
     return repr(self._list) 
    def __str__(self): 
     return str(self._list) 
    def __len__(self): 
     return len(self._list) 
    def __getitem__(self, index): 
     return self._list[index] 
    def __setitem__(self, index, value): 
     if not isinstance(value, self.allowedClasses): 
      raise TypeError('Value of type %s not allowed!' % value.__class__.__name__) 
     self._list[index] = value 
    def __delitem__(self, index): 
     del self._list[index] 
    def insert(self, index, value): 
     if not isinstance(value, self.allowedClasses): 
      raise TypeError('Value of type %s not allowed!' % value.__class__.__name__) 
     self._list.insert(index, value) 

Используйте его следующим образом:

>>> class A(object): pass 

>>> class B(object): pass 

>>> l = VerifierList((A,)) 
>>> l.append(A()) 
>>> print(l) 
>>> [<__main__.A object at 0x000000000311F278>] 
>>> l.append(B()) 

Traceback (most recent call last): 
    File "<pyshell#228>", line 1, in <module> 
    l.append(B()) 
    File "C:\Python27\lib\_abcoll.py", line 661, in append 
    self.insert(len(self), value) 
    File "<pyshell#204>", line 23, in insert 
    raise TypeError('Value of type %s not allowed!' % value.__class__.__name__) 
TypeError: Value of type B not allowed! 
+0

Благодарим за информацию. Я пытаюсь понять это. Для части коллекции объекты хранятся в _list и обслуживаются/управляются из ссылки на объект (имя), «[» и «]» - это просто операторы, которые перегружены этим определением, правильно? Ничего личного (вам), но мне не нравится VerifierList ((A,)), главным образом потому, что я его, естественно, не понимаю - кроме того, как тип класса загружается в .allowedClass; но мне это не нравится. Я могу удалить проверочную часть и иметь обычный «перечислимый» класс, правильно? С наилучшими пожеланиями – userJohn

+0

Если вам нужен обычный «список», просто используйте встроенный «список». Это просто добавляет тип «безопасность», который, как я думал, был тем, что вы хотели. – Kupiakos

+0

Спасибо за комментарии. Вы правы, но я решил, что мне не нравится, как он был механизирован на этом языке. Я собираюсь с вами предложить и наследовать из «списка» моего класса def является 'class myTest (list): def __init __ (self): list .__ init __ (self) self.data = None self.test = Нет. Но я не понимаю результатов. когда 'a = myTest a.data = [1,2,3,4] a.text = 'hello bob''. Я предполагаю, что это элемент a [0]. Но когда я 'a.append (myTest()), этот элемент фактически является [0]. Кроме того, мой отладчик не показывает никаких атрибутов. С наилучшими пожеланиями и благодарностью. – userJohn

Смежные вопросы