Основная проблема заключается в том, что ваш словарь не знает своего имени. Это нормально; как правило, любое количество имен может быть привязано к объекту Python, и ни одно имя никоим образом не может быть привилегированным по сравнению с другими.Другими словами, в a = {}; b = a
оба a
и b
являются именами одного и того же словаря, а a
не является «настоящим» именем словаря только потому, что он был назначен первым. И на самом деле, словарь не имеет возможности даже знать, какое имя находится в левой части переменной.
Таким образом, один из вариантов заключается в том, чтобы словарь содержал свое собственное имя в качестве ключа. Например:
fruit = {"_name": "fruit"}
fruit["red"] = "cherry"
food[fruit["_name"]] = fruit
Ну, это не помогло, не так ли? Это было сделано так, потому что fruit
теперь уже не является строкой в вложении в словарь food
, поэтому, по крайней мере, Python предоставит вам сообщение об ошибке, если вы его обманете. Но вы на самом деле печатаете «фрукты» еще больше, чем раньше: теперь вы должны вводить его, когда вы создаете словарь в дополнение к тому, когда вы присоединяете его к другому словарю. И в мире есть еще более типичный набор.
Кроме того, имея имя в, словарь является своего рода неудобным; когда вы повторяете словарь, вам нужно написать код, чтобы пропустить его.
Вы могли бы написать функцию, чтобы сделать приложение для вас:
def attach(main, other):
main[other["_name"]] = other
Тогда вам не придется повторять себя, когда вы присоедините к югу от словаря к главному:
fruit = {"_name": "fruit"}
fruit["red"] = "cherry"
attach(food, fruit)
И, конечно же, теперь вы можете создать словарь подкласс, который знает свое имя и может прикрепить именованный подзадач. В качестве бонуса мы можем сделать имя атрибутом словаря, а не хранить его в словаре, в котором будет храниться настоящий словарь.
class NamedDict(dict):
def __init__(self, name="", seq=(), **kwargs):
dict.__init__(self, seq, **kwargs)
self.__name__ = name
def attach(self, other):
self[other.__name__] = other
food = NamedDict("food")
fruit = NamedDict("fruit")
fruit["red"] = "cherry"
food.attach(fruit)
Но у нас еще есть одно повторение, когда NamedDict
изначально определен: food = NamedDict("food")
, например. Как нам обойтись без этого?
Это является возможно, хотя и громоздким и, вероятно, не стоит проблем. Python имеет два типа объектов, которые имеют «внутреннее» имя: классы и функции. Другими словами:
class Foo:
pass
выше не только создает переменную с именем Foo
в текущем пространстве имен, имя класса также удобно хранится в атрибуте класса __name__
. (Функции делают что-то подобное.) Из-за злоупотребления классами и метаклассами мы можем полностью использовать базовый механизм , избегая повторения самих себя: минус Недостаток необходимости писать наши словари, как если бы они были классами!
class NamedDict(dict):
class __metaclass__(type):
def __new__(meta, name, bases, attrs):
if "NamedDict" not in globals(): # we're defining the base class
return type.__new__(meta, name, bases, attrs)
else:
attrs.pop("__module__", None) # Python adds this; do not want!
return meta.NamedDict(name, **attrs)
class NamedDict(dict):
def __init__(self, name, seq=(), **kwargs):
dict.__init__(self, seq, **kwargs)
self.__name__ = name
def attach(self, other):
self[other.__name__] = other
__call__ = NamedDict
Теперь, вместо определения наших словарей обычного способа, мы объявляем их как подклассы NamedDict
. Благодаря метаклассу подклассификация внешнего класса NamedDict
фактически создает экземпляры внутреннего класса NamedDict
(который аналогичен предыдущему). Атрибуты подкласса, который мы определяем, если таковые имеются, становятся элементами в словаре, такими как аргументы ключевого слова dict()
.
class food(NamedDict): pass
class fruit(NamedDict): red = "cherry"
# or, defining each item separately:
class fruit(NamedDict): pass
fruit["red"] = "cherry"
food.attach(fruit)
В качестве бонуса, вы можете определить NamedDict
на «регулярный» путь, по инстанцировании его как класс:
fruit = NamedDict("fruit", red="cherry")
быть предупрежден, хотя: «класс, который действительно словарь» это довольно нестандартная идиома для Python, и я бы предположил, что вы никогда на самом деле этого не делаете, поскольку другие программисты не найдут ее совершенно ясной. Тем не менее, это то, как это можно сделать в Python.
Если «не делает то, что мне нужно» означает «не поддерживается языком и выдает ошибку», это правильно. Это может показаться вам «неуклюжим», но вы уже определили правильное решение. – larsks
'Food ['Fruit'] = Fruit' кажется правильным путем. Словари предназначены для индексирования ключами. В этом случае у вас есть Food, который является словарем строковых ключей и значениями словаря. Почему бы вам не захотеть установить в нем ключ? –
В Python и даже на большинстве языков ваши переменные должны начинаться с нижнего регистра. Заглавная первая буква зарезервирована для имен классов. – Soviut