Dict-подобный объект без __getitem__, __setitem__

Если вы делаете

import gdbm
db = gdbm.open('foo', 'cs')

Вы получаете объект, который:

<gdbm.gdbm at 0x7f0982b9aef0>

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

db['foo'] = 'bar'
print db['foo']

Я хотел использовать их из Twisted и сделать обертку для __getitem__ а также __setitem__ который возвращает отложенные. Однако я заметил кое-что своеобразное:

In [42]: dir(db)
Out[42]: ['close', 'firstkey', 'has_key', 'keys', 'nextkey', 'reorganize', 'sync']

Этот объект не имеет __getitem__ а также __setitem__, Попытка любого из них дает ошибку доступа к атрибуту. Тем не менее, он ведет себя как словарь. Что это за объект?

(Я подозреваю, что это объект расширения C, но я нахожу странным, что у него есть методы доступа типа dict, но нет __getitem__ а также __setitem__ методы. Указатель на документ Python, описывающий это поведение, был бы полезен.)

Далее: как бы вы получили ссылки на db.__getitem__ а также db.__setitem__ если бы вы хотели обернуть их в отсрочку? Единственное решение, которое я вижу, - это обернуть db в служебный класс:

class Db:
    def __init__(self, db):
         self.db = db

    def __getitem__(self, x):
         return self.db[x]

    ...

Но, может быть, я упускаю что-то очевидное?

1 ответ

Решение

gdbm действительно модуль C; вместо этого объект реализует протокол отображения C-API.

Смотрите исходный код для PyMappingMethods структура с указателями функций.

Вы могли бы использовать operator.getitem() чтобы получить доступ к ключам:

>>> from operator import getitem
>>> db['foo'] = 'bar'
>>> getitem(db, 'foo')
'bar'

Вы могли бы обернуть getitem() в functools.partial() чтобы сделать его эффективным с одним аргументом:

>>> from functools import partial
>>> gi = partial(getitem, db)
>>> gi('foo')
'bar'

Как getitem а также partial реализованы в C, эта комбо всегда будет быстрее, чем пользовательские объекты, функции или лямбды, чтобы обернуть доступ.

Другие вопросы по тегам