2015-11-09 3 views
0

EDIT: я добавил класс и некоторую информацию, увидев новое сообщение.

Я создал класс, который расширяет dict и set (точнее, я протянул collections.abc.MutableMapping и MutableSet). Теперь я хочу правильно переопределить метод keys().Как правильно переопределить ключи методов() при расширении dict (в python3)

Этот класс представляет собой набор других объектов, называемый Measurand:

class Measurands(MutableSet, MutableMapping): 
    @property 
    def measurands(self): 
     return self._measurands 


    @measurands.setter 
    def measurands(self, val): 
     self._measurands = [] 

     for el in val: 
      self.add(el) 


    def __init__(self, arg=None): 
     if arg is None: 
      self.measurands = [] 
     else: 
      try: 
       measurands = arg.measurands 
      except AttributeError: 
       if isinstance(arg, Iterable): 
        measurands = list(arg) 
       else: 
        measurands = [arg] 

      self.measurands = measurands 


    def __iter__(self): 
     return iter(self.measurands) 


    def __getitem__(self, key): 
     for m in self: 
      if m.id == key: 
       return m 

     raise KeyError(key) 


    def __contains__(self, el_x): 
     is_in = False 

     for el in self: 
      if el_x.id == el.id: 
       is_in = True 
       break 

     return is_in 


    def add(self, el): 
     try: 
      self[el.id].session_ids |= el.session_ids 
     except KeyError: 
      self[el.id] = Measurand(el) 


    def _discard(self, key): 
     res = False 

     for i, m in enumerate(self): 
      if m.id == key: 
       del self.measurands[i] 
       res = True 
       break 

     return res 


    def __delitem__(self, key): 
     res = self._discard(self, key) 

     if not res: 
      raise KeyError(key) 

    def discard(self, key): 
     self._discard(self, key) 


    def remove(self, key): 
     self.__delitem__(self, key) 


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


    def __setitem__(self, key, value): 
     res = False 
     value_true = Measurand(value) 

     for i, m in enumerate(self): 
      if m.id == key: 
       res = True 

       if value.id == key: 
        self.measurands[i] = value_true 
       else: 
        raise KeyError(key) 

       break 

     if not res: 
      self.measurands.append(value_true) 


    def __str__(self): 
     string = "Measurands({" 

     for m in self: 
      string += str(m) 
      string += ", " 

     if string: 
      string = string[:-2] 

     string += "})" 

     return string 

Проблема является метод по умолчанию keys возвращает «список» Measurand объектов. Это не то, что я хочу. Ключами должны быть имущество id объектов Measurand.

На данный момент я возвращаю простой list, но я бы вернул dict_keys или объект collection.abc.KeysView. К несчастью, dict_keys не является глобальным именем.

  1. Где dict_keys?
  2. Это правильный/питонический способ сделать это?
+2

* «Я хочу правильно переопределить метод' dict() '" * - что? 'dict' - не метод. Вы хотите иметь возможность делать 'dict (instance_of_your_thing)'? Не могли бы вы дать [mcve] вашей реализации и объяснить проблему на примере? – jonrsharpe

+0

Судя по названию, я думаю, он имел в виду, что хочет правильно переопределить 'keys()' и сделал опечатку в актуальном вопросе – wpercy

+0

@wilbur ах! Это имеет смысл. OP? – jonrsharpe

ответ

0

Это уже обработано для Вас! collections.abc.MutableMapping включает разумную реализацию по умолчанию keys, которая обеспечивает тот же интерфейс, что и dict.keys.

Просто удалите свой метод keys, и вы будете использовать унаследованную реализацию.

+0

Ну, я пропустил сообщение о полезной информации. См. Обновленный вопрос. –

+1

@MarcoSulla: Он не возвращает список Measurands. Вы испортили свой '__iter__'; он перебирает значения вместо ключей. Исправьте это, и реализация унаследованных «ключей» будет работать. – user2357112

+0

'__iter__' верен. Если я делаю 'for m in mm', где' mm' - объект 'Measurands', я хочу, чтобы' m' был i-м объектом 'Measurand', а не его id. Если вы заметили, класс 'Measurand' представляет собой комбинацию' set' и 'dict', которые я создал, потому что вы не можете сделать« набор »несмонтируемых объектов. –

0

Я не смог найти какой-либо способ бросить кое-что к dict_keys типа, но после прочтения PEP, который ввел новый способ доступа ключей и значений (PEP 3106), это выглядит как dict_keys был введен

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

Принимая это во внимание множество подобных или, это выглядит как вы могли бы уйти с возвратом объекта-генератора с помощью вашего метода keys() вместо списка.

Вот псевдо-код из PEP:

class dict: 

    # Omitting all other dict methods for brevity. 

    def keys(self): 
     return d_keys(self) 

class d_keys: 

    def __init__(self, d): 
     self.__d = d 

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

    def __contains__(self, key): 
     return key in self.__d 

    def __iter__(self): 
     for key in self.__d: 
      yield key 
0

Документация Python3 говорит, что dict.keys() тип возвращаемого значения (т.е. вид) является «набор типа», поэтому ваше возвращение значение должно быть «установлено «как».

объекты, возвращенные dict.keys(), dict.values ​​() и dict.items() являются объекты вида. Они обеспечивают динамический просмотр записей словаря , а это означает, что при изменении словаря вид отражает эти изменения.

Словарь просмотры могут повторяться через, чтобы получить их соответствующих данных, и членство поддержки тесты:

....

просмотры

ключей устанавливаются подобным, поскольку их записи уникальны и hashable. Если все значения хешируются, так что пары (ключ, значение) уникальны и хешируются, тогда представление элементов также задано. (Значения значений не рассматриваются как set-like, поскольку записи, как правило, не уникальны.) Для представлений в виде множества всех операций, определенных для абстрактной базы класса collection.abc.Set доступны (например, ==, <, или ^).

Полный текст здесь: https://docs.python.org/3/library/stdtypes.html#dict-views