Ответ 1
Проверьте документацию эмуляцию типов контейнеров. В вашем случае первый параметр add
должен быть self
.
Я хочу написать пользовательский класс, который ведет себя как dict
- так что я наследую от dict
.
Мой вопрос, однако, заключается в следующем: нужно ли создать частный член dict
в моем методе __init__()
?. Я не вижу смысла в этом, так как у меня уже есть поведение dict
, если я просто наследую от dict
.
Может ли кто-нибудь указать, почему большинство фрагментов наследования выглядят так, как показано ниже?
class CustomDictOne(dict):
def __init__(self):
self._mydict = {}
# other methods follow
Вместо простого...
class CustomDictTwo(dict):
def __init__(self):
# initialize my other stuff here ...
# other methods follow
На самом деле, я думаю, я подозреваю, что ответ на вопрос заключается в том, что пользователи не могут напрямую обращаться к вашему словарю (т.е. им нужно использовать предоставленные вами методы доступа).
Однако как насчет оператора доступа к массиву []
? Как это реализовать? До сих пор я не видел примера, который показывает, как переопределить оператор []
.
Итак, если функция доступа []
не предоставляется в пользовательском классе, унаследованные базовые методы будут работать в другом словаре?
Я попробовал следующий фрагмент, чтобы проверить свое понимание наследования Python:
class myDict(dict):
def __init__(self):
self._dict = {}
def add(self, id, val):
self._dict[id] = val
md = myDict()
md.add('id', 123)
print md[id]
Я получил следующую ошибку:
KeyError: < встроенная функция id >
Что не так с кодом выше?
Как мне исправить класс myDict
, чтобы я мог писать такой код?
md = myDict()
md['id'] = 123
[изменить]
Я редактировал приведенный выше пример кода, чтобы избавиться от глупой ошибки, которую я сделал, прежде чем я удалился от своего стола. Это была опечатка (я должен был заметить ее из сообщения об ошибке).
Проверьте документацию эмуляцию типов контейнеров. В вашем случае первый параметр add
должен быть self
.
class Mapping(dict):
def __setitem__(self, key, item):
self.__dict__[key] = item
def __getitem__(self, key):
return self.__dict__[key]
def __repr__(self):
return repr(self.__dict__)
def __len__(self):
return len(self.__dict__)
def __delitem__(self, key):
del self.__dict__[key]
def clear(self):
return self.__dict__.clear()
def copy(self):
return self.__dict__.copy()
def has_key(self, k):
return k in self.__dict__
def update(self, *args, **kwargs):
return self.__dict__.update(*args, **kwargs)
def keys(self):
return self.__dict__.keys()
def values(self):
return self.__dict__.values()
def items(self):
return self.__dict__.items()
def pop(self, *args):
return self.__dict__.pop(*args)
def __cmp__(self, dict_):
return self.__cmp__(self.__dict__, dict_)
def __contains__(self, item):
return item in self.__dict__
def __iter__(self):
return iter(self.__dict__)
def __unicode__(self):
return unicode(repr(self.__dict__))
o = Mapping()
o.foo = "bar"
o['lumberjack'] = 'foo'
o.update({'a': 'b'}, c=44)
print 'lumberjack' in o
print o
In [187]: run mapping.py
True
{'a': 'b', 'lumberjack': 'foo', 'foo': 'bar', 'c': 44}
Подобно этому
class CustomDictOne(dict):
def __init__(self,*arg,**kw):
super(CustomDictOne, self).__init__(*arg, **kw)
Теперь вы можете использовать встроенные функции, такие как dict.get()
как self.get()
.
Вам не нужно обертывать скрытый self._dict
. У вашего класса уже есть a dict.
Для полноты, вот ссылка на документацию, упомянутую @björn-pollex для последнего Python 2.x(2.7.7 на момент написания):
(Извините, что не использовал функцию комментариев, мне просто не разрешено делать это с помощью stackoverflow.)
Проблема с этим фрагментом кода:
class myDict(dict):
def __init__(self):
self._dict = {}
def add(id, val):
self._dict[id] = val
md = myDict()
md.add('id', 123)
... заключается в том, что ваш метод "добавить" (... и любой метод, который вы хотите быть членом класса) должен иметь явное "я", объявленное как его первый аргумент, например:
def add(self, 'id', 23):
Чтобы реализовать перегрузку оператора для доступа к элементам по ключу, просмотрите docs для магических методов __getitem__
и __setitem__
.
Обратите внимание, что поскольку Python использует Duck Typing, на самом деле не может быть причин для получения вашего пользовательского класса dict из языка dict class - не зная больше о том, что вы пытаетесь сделать (например, если вам нужно пройти экземпляр этого класса в какой-то код, который будет разбит, если isinstance(MyDict(), dict) == True
), вам может быть лучше просто реализовать API, который сделает ваш класс достаточно диктоподобным и останавливается там.
Вот альтернативное решение:
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__dict__ = self
a = AttrDict()
a.a = 1
a.b = 2
Не наследуй от Python встроенного dict, никогда! например, метод update
не будет использовать __setitem__
, они много делают для оптимизации. Используйте UserDict.
from collections import UserDict
class MyDict(UserDict):
def __delitem__(self, key):
pass
def __setitem__(self, key, value):
pass