Переопределение добавляет метод после наследования от Списка Python

Я хочу создать список, который может только принять определенные типы. По сути, я пытаюсь наследоваться списку в Python и переопределяю добавление () метод как так:

class TypedList(list):
    def __init__(self, type):
        self.type = type

    def append(item)
        if not isinstance(item, type):
            raise TypeError, 'item is not of type %s' % type
        self.append(item)  #append the item to itself (the list)

Это желание причины, которую бесконечный цикл, потому что тело добавляет () называет само, но я не уверен, что сделать кроме использования self.append (объект).

Как я должен пойти о выполнении этого?

13
задан chaindriver 15 August 2010 в 12:54
поделиться

4 ответа

Я внес некоторые изменения в ваш класс. Кажется, это работает.

Пара предложений: не используйте тип в качестве ключевого слова - тип является встроенной функцией. Доступ к переменным экземпляра Python осуществляется с помощью self. префикс. Поэтому используйте self. <Имя переменной> .

class TypedList(list):
    def __init__(self, type):
        self.type = type

    def append(self, item):
        if not isinstance(item, self.type):
            raise TypeError, 'item is not of type %s' % self.type
        super(TypedList, self).append(item)  #append the item to itself (the list)

from types import *
tl = TypedList(StringType)
tl.append('abc')
tl.append(None)
Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    tl.append(None)
  File "<pyshell#22>", line 7, in append
    raise TypeError, 'item is not of type %s' % self.type
TypeError: item is not of type <type 'str'>
17
ответ дан 1 December 2019 в 17:15
поделиться

вместо self.append(item) используйте super(TypedList, self).append(item) (см. http://docs.python.org/library/functions.html#super)

3
ответ дан 1 December 2019 в 17:15
поделиться

Во-первых, не делая этого.

Если вам не нужно что-то типа X в вашем списке, почему вы помещаете это туда?

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

По той же причине, по которой вы не пытаетесь 'строка' / 2.0 , у вас такой же контроль над тем, что помещается в список. Так как список будет содержать разнородные типы, в лучшем случае TypedList переместит ошибку времени выполнения TypeError из того места, где вы используете элемент, вперед во времени туда, где вы добавляете его в список. Учитывая, что Python duck-typing явно проверяет isinstance , предотвращает последующее расширение списка, чтобы он содержал экземпляры, отличные от типа , но не дает никаких преимуществ.

добавлена ​​информация OrderedDict :

Для каждого запроса в комментарии, предполагая, что Python 2.7 или выше коллекций. OrderedDict сделает это. На этой странице документации, учитывая 2.4 или выше, вы должны добавить один .

1
ответ дан 1 December 2019 в 17:15
поделиться

Я хочу создать список, в котором можно только принимать определенные типы. Таким образом, я пытается наследовать от списка в Python

Не лучший подход! В списках Python так много методов изменения, что вам придется переопределить кучу (и, вероятно, вы забудете некоторые).

Вместо этого оберните список, унаследованный от collections.MutableSequence , и добавьте свои проверки в очень немногие методы «точки доступа», на которых полагается MutableSequence реализовать все остальные.

import collections

class TypedList(collections.MutableSequence):

    def __init__(self, oktypes, *args):
        self.oktypes = oktypes
        self.list = list()
        self.extend(list(args))

    def check(self, v):
        if not isinstance(v, self.oktypes):
            raise TypeError, v

    def __len__(self): return len(self.list)

    def __getitem__(self, i): return self.list[i]

    def __delitem__(self, i): del self.list[i]

    def __setitem__(self, i, v):
        self.check(v)
        self.list[i] = v

    def insert(self, i, v):
        self.check(v)
        self.list.insert(i, v)

    def __str__(self):
        return str(self.list)

Аргумент oktypes обычно представляет собой кортеж типов, которые вы хотите разрешить, но, конечно, можно передавать туда один тип (и, сделав этот тип абстрактным базовым классом, ABC, вы можете легко выполнить любую проверку типов по вашему выбору, но это уже другая проблема).

Вот пример кода, использующего этот класс:

x = TypedList((str, unicode), 'foo', 'bar')
x.append('zap')
print x
x.append(23)

вывод:

['foo', 'bar', 'zap']
Traceback (most recent call last):
  File "tl.py", line 35, in <module>
    x.append(23)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_abcoll.py", line 556, in append
    self.insert(len(self), value)
  File "tl.py", line 25, in insert
    self.check(v)
  File "tl.py", line 12, in check
    raise TypeError, v
TypeError: 23

Обратите внимание, в частности, что у нас есть не переопределено append - но append есть и ведет себя как и ожидалось.

Не столь секретный, что скрывается за этой магией, раскрывается в трассировке: _abcoll.py (модуль реализации для абстрактных базовых классов в модуле collections ), в строке 556 реализует append, вызывая нашу insert - которую мы , конечно, имеем , которая должным образом переопределена.

Этот «шаблонный метод проектирования шаблонов» (абсолютно ценный для всех видов ООП - поищите мои доклады о шаблонах проектирования на YouTube, и вы узнаете, почему ;-), среди других преимуществ, дает нам «узкую точку» эффект "Я упоминал ранее: добавляя некоторые проверки для очень немногих методов, которые вы должны реализовать, вы получаете преимущество, заключающееся в том, что эти проверки применяются к _все__ другим соответствующим методам (а у изменяемых последовательностей в Python их много ;-).

Неудивительно, что мы получаем очень мощный и классический шаблон дизайна «за кулисами», потому что вся идея этой стратегии реализации исходит прямо из бессмертной классической книги «Шаблоны дизайна» (авторы которой часто вместе называется группой из четырех ";-): предпочитают композицию объектов наследованию . Наследование (от конкретных классов) - это очень жесткий механизм связывания, полный" ошибок ", как только вы пытаетесь используйте его, чтобы делать что-нибудь, даже немного выходящее за его строгие пределы; композиция чрезвычайно гибкая и полезная, а наследование от соответствующих абстрактных классов может очень хорошо дополнить картину.

Превосходный "Эффективный C ++" Скотта Мейерса. , пункт 33 формулирует это еще сильнее: делает классы, не являющиеся листами, абстрактными . Поскольку под «нелистовыми» он подразумевает «любой класс, который когда-либо унаследован от», эквивалентная формулировка будет «никогда не унаследовать от конкретного класса».

Скотт, конечно, пишет в контексте C ++, но Пол Хаар дает точно такой же совет для Java, сформулированный как Не подклассифицируйте конкретные классы - и я обычно во-вторых, это для Python, хотя я предпочитаю более мягкую формулировку группы из четырех человек, предпочитаю композицию наследованию (конкретного класса) (но я понимаю, что и Скотт, и Пол часто пишут для аудитории, которая очень нуждается в прямой и строго сформулированный совет, почти сформулированный как «заповеди», а не совет, не более мягкий, который они могли бы слишком легко проигнорировать во имя своего удобства ;-).

47
ответ дан 1 December 2019 в 17:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: