Переопределение методов набора в Python

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

Если я переопределю add, remove, __contains__, __str__, update, __iter__, будет ли этого достаточно, чтобы другие операции вели себя должным образом, или мне нужно переопределить что-нибудь еще?


person Casebash    schedule 26.10.2009    source источник
comment
@Casebash: пожалуйста, не комментируйте свой вопрос. Даже хорошее предложение - в конечном итоге - довольно глупо. Другие люди хотят, чтобы ваш вопрос и выбранный ответ были без лишнего вздора.   -  person S.Lott    schedule 26.10.2009


Ответы (2)


Работа с абстрактными классами collections, как предлагает @ kaizer.se, является подходящим решением в 2.6 (не уверен, почему вы хотите вызвать super - какие функции вы пытаетесь делегировать, которые не могут быть лучше реализованы путем сдерживания, а не наследования ?! ).

Это правда, что вы не получаете update - предоставляя абстрактные методы, вы получаете __le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__ __sub__, __xor__, and isdisjoint (от collections.Set) плюс clear, pop, remove, __ior__, __iand__, __ixor__, and __isub__ (от collections.MutableSet), что намного больше, чем вы получили бы от подкласса set (где у вас было бы чтобы переопределить каждый интересующий метод). Вам просто нужно будет предоставить другие методы, которые вы хотите.

Обратите внимание, что абстрактные базовые классы, такие как collections.Set, сильно отличаются от конкретных классов, включая встроенные функции, такие как set и (в 2.6) старый добрый sets.Set, устаревшие, но все еще присутствующие (удалены в Python 3). ABC предназначены для наследования (и могут затем синтезировать некоторые методы от вас, как только вы реализуете все абстрактные методы, как вы должны) и, во-вторых, для «регистрации» классов, чтобы они выглядели так, как будто они унаследованы от них, даже если они не (чтобы сделать isinstance более полезным и полезным).

Вот рабочий пример для Python 3.1 и 2.6 (нет веских причин для использования 3.0, поскольку 3.1 имеет только преимущества перед ним, без недостатков):

import collections

class LowercasingSet(collections.MutableSet):
  def __init__(self, initvalue=()):
    self._theset = set()
    for x in initvalue: self.add(x)
  def add(self, item):
    self._theset.add(item.lower())
  def discard(self, item):
    self._theset.discard(item.lower())
  def __iter__(self):
    return iter(self._theset)
  def __len__(self):
    return len(self._theset)
  def __contains__(self, item):
    try:
      return item.lower() in self._theset
    except AttributeError:
      return False
person Alex Martelli    schedule 26.10.2009
comment
Его можно обобщить, используя везде key(item) вместо item.lower() - ›KeySet("Aa", key=operator.methodcaller('lower')). - person jfs; 26.10.2009
comment
Почему вы делаете подкласс от Set, а не от MutableSet? Кто-нибудь, кроме меня, думает, что это очень сбивает с толку, что модуль коллекций представляет собой смесь реальных коллекций (deque) и ABC? - person u0b34a0f6ae; 26.10.2009
comment
Стоит отметить, что Set - это не то же самое, что set. - person Casebash; 26.10.2009
comment
@JF и kaizer, моя глупая опечатка - я упомянул разницу Set / MutableSet в тексте, затем использовал первое в коде, теперь исправлено, tx. Да, Casebash, Python чувствителен к регистру (также sets.Set отличается от collections.Set в Py 2.6, поскольку они находятся в разных модулях и пространствах имен). @kaizer, да, может быть, нам стоило поместить ABC в другой модуль (но abc.py используется для низкоуровневой инфраструктуры ABC, никакое другое имя модуля не является убедительным консенсусом). - person Alex Martelli; 26.10.2009
comment
@JF, отличная идея - такая параметризация оказалась очень полезной для sort, min, max, ... и по другой оси в defaultdict. - person Alex Martelli; 26.10.2009
comment
Для справки в будущем здесь есть рецепт KeyedSet, основанный на MutableSet. code.activestate.com/recipes/576932 - person u0b34a0f6ae; 27.10.2009

В Python 2.6:

import collections
print collections.MutableSet.__abstractmethods__
# prints:
# frozenset(['discard', 'add', '__iter__', '__len__', '__contains__'])

подкласс collections.MutableSet и переопределите методы в списке выше.

сам метод обновления очень прост, учитывая, что реализован минимум, указанный выше

def update(self, iterable):
    for x in iterable:
        self.add(x)
person u0b34a0f6ae    schedule 26.10.2009
comment
Плюс я не могу вызвать супер (используя Python 3.0) - person Casebash; 26.10.2009
comment
@Casebash: включите в вопрос информацию о Python 3.0, а не комментарий к ответу. - person S.Lott; 26.10.2009