Я как бы наполовину прочитал твой вопрос, написал ниже, а затем перечитал твой вопрос и понял, что ответил на немного другой вопрос. Но я думаю, что ниже на самом деле все еще дает ответ после рода. Если вы так не думаете, сделайте вид, что задали этот более общий вопрос, который, я думаю, включает в себя ваш подвопрос:
"Почему Python не предоставляет какой-либо встроенный способ обработки атрибутов и элементов как взаимозаменяемых?"
Я задумался над этим вопросом, и я думаю, что ответ очень прост. Когда вы создаете тип контейнера, очень важно различать атрибуты и items . Любой достаточно хорошо разработанный контейнерный тип будет иметь ряд атрибутов - часто, хотя и не всегда, методов - которые позволяют ему изящно управлять своим содержимым. Так, например, у dict есть items
, values
, keys
, iterkeys
и так далее. Все эти атрибуты доступны с использованием нотации .
. К элементам, с другой стороны, обращаются, используя обозначение []
. Так что не может быть никаких столкновений.
Что происходит, когда вы включаете доступ к элементу, используя нотацию .
? Внезапно у вас есть перекрывающиеся пространства имен . Как вы справляетесь со столкновениями сейчас? Если вы создаете подкласс и диктуете эту функциональность, либо вы, как правило, не можете использовать такие ключи, как items
, либо вам необходимо создать какую-то иерархию пространства имен. Первый вариант создает правило, которое является обременительным, сложным для исполнения и неукоснительным. Второй вариант создает раздражающую степень сложности без полного решения проблемы коллизий, поскольку вам все еще нужно иметь альтернативный интерфейс, чтобы указать, хотите ли вы items
элемент или items
атрибут.
Теперь, для некоторых видов очень примитивных типов это приемлемо. Наверное, поэтому в стандартной библиотеке, например, namedtuple
. (Но обратите внимание, что namedtuple
подвержен этим самым проблемам, поэтому, вероятно, он был реализован как фабричная функция (предотвращает наследование) и использует странные, закрытые имена методов, такие как _asdict
.)
Также очень, очень, очень легко создать подкласс object
без (публичных) атрибутов и использовать на нем setattr
. Даже довольно легко переопределить __getitem__
, __setitem__
и __delitem__
для вызова __getattribute__
, __setattr__
и __delattr__
, так что доступ к элементу становится синтаксическим сахаром для getattr()
, setattr()
и т. Д. (Хотя это немного более сомнительно, так как вызывает несколько неожиданное поведение.)
Но для любого хорошо разработанного класса контейнеров, который вы хотите иметь возможность расширять и наследовать, добавляя новые полезные атрибуты, гибрид __getattr__ + __getitem__
был бы, честно говоря, огромным PITA.