Comments 41
Как быть, если ключ совпадает с именем метода? Имхо, не нужно путать сущности: интерфейс доступа к данным должен быть один.
0
Такая ситуация не будет мешать нативным фунцкиям словаря, так что всегда остается возможность написать
Интерфейс доступа к данным остался один, только теперь его можно синтаксически написать по-разному: оба варианта работают эквивалентно.
a["copy"]
.Интерфейс доступа к данным остался один, только теперь его можно синтаксически написать по-разному: оба варианта работают эквивалентно.
0
Тут возникает неопределенность: через __getitem__ можно гарантированно получить хранимое значение, через __getattr__ — возможно нарваться на built-in метод или метод/свойство/атрибут класса наследника, что создаст двоякость. С __setattr__ и __setitem__ тоже самое — неопределенность:
>>> foo = Dict()
>>> foo.update = 'bar'
>>> foo.update
<built-in method update of Dict object at 0xb74e580c>
тогда как ожидалось все же 'bar'.
Получается, что безопасней пользоваться dict-like интерфейсом, чтобы гарантировать получение нужного значения. Не зачем усложнять себе жизнь.
>>> foo = Dict()
>>> foo.update = 'bar'
>>> foo.update
<built-in method update of Dict object at 0xb74e580c>
тогда как ожидалось все же 'bar'.
Получается, что безопасней пользоваться dict-like интерфейсом, чтобы гарантировать получение нужного значения. Не зачем усложнять себе жизнь.
+7
не знаю как у вас, но у меня после ваших манипуляций
foo.update
возвращает 'bar'
. Но это порождает другую проблему: перекрытие нативных методов с последующими трудноуловимыми багами там, где они используются.0
Потому что я использовал реализацию 2. Вариант 3 не будет работать, если задан __slots__. В любом случае, в третьем варианте та жа проблема, только вид с другой стороны.
0
рекурсивный вариант
У Вас при инициализации чего-то вида
У Вас при инициализации чего-то вида
c = Dict({'a':1,'b':{'c':3,'d':4}})
, судя по коду, не будут доступны через точку аттрибуты внутренних словарей+1
Да, рекурсивный вариант не предполагался, хотя можно написать так:
Кстати, рекурсивным вариантом вроде того, что вы предложили, очень удобно оборачивать какие-то распаршеные конфиги или другие данные, полученные из yaml или json для последующей работы с ними.
Dict({'a':1,'b':Dict({'c':3,'d':4})})
.Кстати, рекурсивным вариантом вроде того, что вы предложили, очень удобно оборачивать какие-то распаршеные конфиги или другие данные, полученные из yaml или json для последующей работы с ними.
0
UFO just landed and posted this here
В такой реализации атрибуты объекта и ЕСТЬ значениями в словаре (не считая нативных методов класа dict), так что они не могут «путаться». Хотя да, согласен проблемы могут вылезти, например, если отнаследоватся от Dict и добавить в него новые свойства, они не будут видны как значения(item) в словаре-экземпляре этого класа, хотя будут видны как атрибуты(attr). Но эту проблему можно решить с помощью метакласа, что, по секрету, и было сделанно в системе, где это используются.)
0
UFO just landed and posted this here
Вы правы. Расширенную реализацию идеи, с использованием метакласса, которая частично решает проблему:
Такая реализация во-первых позволяет объектам иметь методы, определенные в класах-наследниках Dict, которые при этом не будут элементами словаря, а во-вторых поддерживаются как атрибуты и как элементы свойства по-умолчанию, определенные в класах-наследниках.
def validDictProperty(name, value):
return not callable(value) and not isinstance(value, (property, classmethod, staticmethod))
class DictMetaclass(type):
def __init__(cls, name, bases, namespace):
cls.default = {}
for base in bases:
if hasattr(base, "default"):
cls.default.update(base.default)
cls.default.update((k, v) for k, v in namespace.items() if validDictProperty(k, v))
class Dict(dict):
__metaclass__ = DictMetaclass
def __new__(cls, *args, **kwargs):
self = dict.__new__(cls)
self.update(cls.default)
self.__dict__ = self
return self
Такая реализация во-первых позволяет объектам иметь методы, определенные в класах-наследниках Dict, которые при этом не будут элементами словаря, а во-вторых поддерживаются как атрибуты и как элементы свойства по-умолчанию, определенные в класах-наследниках.
0
UFO just landed and posted this here
Вообще динамически подтыкаемые аттрибуты и методы сами по себе бомба с часовым механизмом.
0
Возможно не «функционал словаря», а функциональность словаря?)
+1
UFO just landed and posted this here
UFO just landed and posted this here
в 3 варианте циклическая ссылка, со всеми вытекающими…
это неправильный «синтаксический сахар», такая практика не приветствуется!
это неправильный «синтаксический сахар», такая практика не приветствуется!
0
Словарь — очень эффективная структура, с точки зрения времени доступа к данным. Логично предположить, что в словари (и уникальные наборы) собирают часто запрашиваемую информацию. Поэтому очень странно видеть подобную реализацию словаря, когда даже в официальных рекомендациях по оптимизации кода советуют избегать обращения через точку и пользоваться малочитаемыми хаками, если алгоритм часто повторяет это обращение.
+3
UFO just landed and posted this here
Уважаемый tanenn очень хорошо описал отношение к этой «фишке» в комментарие выше: habrahabr.ru/blogs/python/129201/#comment_4276323
Конечно, если вам нужен словарь, как «очень эффективная структура, с точки зрения времени доступа к данным», то никакой синтаксический сахар и вообще любые слои над стандартной библиотекой ни к чему.
Конечно, если вам нужен словарь, как «очень эффективная структура, с точки зрения времени доступа к данным», то никакой синтаксический сахар и вообще любые слои над стандартной библиотекой ни к чему.
0
Слои над стандартной библиотекой решают прикладные задачи — унификация интерфейсов и отражение предметной области в коде. Они полезны как раз потому, что не являются простым синтаксическим сахаром.
А вот слой «структуры данных как в JavaScript» поверх отдельно взятой структуры данных, которая сама по себе не отражает никакой семантики из предметной области, а служит лишь «строительным блоком» — настоящий overengineering. С печальными последствиями на производительности.
Кстати, хороший «синтаксический сахар» — это тот, который вводится на уровне конструкций языка, либо способен компилироваться в код без side-эффектов и деградаций в производительности.
А вот слой «структуры данных как в JavaScript» поверх отдельно взятой структуры данных, которая сама по себе не отражает никакой семантики из предметной области, а служит лишь «строительным блоком» — настоящий overengineering. С печальными последствиями на производительности.
Кстати, хороший «синтаксический сахар» — это тот, который вводится на уровне конструкций языка, либо способен компилироваться в код без side-эффектов и деградаций в производительности.
+2
Спасибо за ссылку. Многие вещи по отдельности встречал в разных статьях, но здесь они очень хорошо собраны и описаны.
0
В осуждаемом многими за некошерность фреймворке web2py есть качественная реализация первого варианта, описанного в статье — класс Storage
class Storage(dict):
"""
A Storage object is like a dictionary except `obj.foo` can be used
in addition to `obj['foo']`.
>>> o = Storage(a=1)
>>> print o.a
1
>>> o['a']
1
>>> o.a = 2
>>> print o['a']
2
>>> del o.a
>>> print o.a
None
"""
def __getattr__(self, key):
if key in self:
return self[key]
else:
return None
def __setattr__(self, key, value):
if value == None:
if key in self:
del self[key]
else:
self[key] = value
def __delattr__(self, key):
if key in self:
del self[key]
else:
raise AttributeError, "missing key=%s" % key
def __repr__(self):
return '<Storage ' + dict.__repr__(self) + '>'
def __getstate__(self):
return dict(self)
def __setstate__(self, value):
for (k, v) in value.items():
self[k] = v
0
Интересно будет ли работать такой код под PyPy 1.6+ Может пробовали?
0
Это то что я хотел при работе со словарями, тоже думал о такой реализаций, но без проблем этого не сделать, поэтому желания поубавилось. Но если приходится часто работать с какой либо структурой, которая статична, то пытаюсь использовать именованные кортежи, но это лишь покрывает малую долю желаемого.
0
¿а чем вас не устаивает просто в лоб:
class D(object): pass d = D() d.foo = "foo"
0
Тоже делал схожую штуку (она делала разбор очень сложного конфига в DOM, состоящий из подобны оюъектов), из нее хочу добавить полезный сниппет метода:
Правда в итоге я пришел к выводу, что pythonic-pythonic-ом, но подобное нестандартное использование очень сильно мешает созданию reusable кода и вообще скорость и корректность его восприятия.
На питоне можно сделать миллион очень необычных и извилистых конструкций, но чем дальше, тем реже я пользуюсь даже генераторами с лямбдами.
def get_public_attrs(self):
return filter(lambda (a,b): a[0] != '_', self.__dict__.items())
Правда в итоге я пришел к выводу, что pythonic-pythonic-ом, но подобное нестандартное использование очень сильно мешает созданию reusable кода и вообще скорость и корректность его восприятия.
На питоне можно сделать миллион очень необычных и извилистых конструкций, но чем дальше, тем реже я пользуюсь даже генераторами с лямбдами.
0
В топку такое решение! Не используйте его — это создатель циклических ссылок. То есть у вас приложение будет неконтролируемо жрать память на пустом месте, если вы будете надеятся на короткую живучесть этих словарей (и их будет много притом). То есть вместо дешевой сборки объектов с более менее детерминированной деструкцией вы получити сборку мусора циклических ссылок, с недетерминированной деструкцией (RAII — против такого).
0
А разве существующий в питоне из коробке класс UserDict не решает всех проблем без лишних велосипедов?
Пруфлинк: docs.python.org/release/2.7/library/userdict.html#module-UserDict
Пруфлинк: docs.python.org/release/2.7/library/userdict.html#module-UserDict
0
Sign up to leave a comment.
Articles
Change theme settings
Реализация объектов-словарей, как в Javascript