あなたが抱えている基本的な問題は、あなたの辞書がそれ自身の名前を知らないということです. これは正常です。一般に、任意の数の名前を 1 つの Python オブジェクトにバインドすることができ、単一の名前が他の名前よりも優先されることは決してありません。つまり、 では、とはa = {}; b = a
どちらも同じ辞書の名前であり、最初に割り当てられたという理由だけで、辞書の「実際の」名前ではありません。実際、辞書は、変数の左側にある名前を知る方法さえありません。a
b
a
したがって、1 つの代替方法は、辞書に独自の名前をキーとして含めることです。例えば:
fruit = {"_name": "fruit"}
fruit["red"] = "cherry"
food[fruit["_name"]] = fruit
まあ、それはあまり役に立ちませんでしたね?fruit
辞書への添付ファイルではもはや文字列ではないため、ある意味でfood
そうしました. しかし、実際には以前よりもさらに多くの "fruit" を入力しています。別の辞書に添付するときだけでなく、辞書を作成するときにも入力する必要があります。そして、一般的にかなり多くのタイピングがあります。
また、名前を辞書の項目として持つのは、ちょっと不便です。辞書を反復処理するときは、それをスキップするコードを作成する必要があります。
添付ファイルを作成する関数を作成できます。
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
しかし、が最初に定義されたときは、まだ 1 つの繰り返しがあります:food = NamedDict("food")
たとえば。どうすればそれを省くことができますか?
可能ですが、扱いにくく、おそらく手間をかける価値はありません。Python には、クラスと関数という「固有の」名前を持つ 2 種類のオブジェクトがあります。言い換えると:
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 で実行できる方法です。