0

わかりました、食べ物という辞書があります。food には 2 つの要素があり、どちらも辞書そのものである、野菜と乳製品です。veg には、根 : カブと茎 : アスパラガスの 2 つの要素があります。乳製品にはチーズ:チェダー、ヨーグルト:ストロベリーがあります。赤:チェリー、黄色:バナナの新しい辞書フルーツもあります。

food['veg']['root'] == 'Turnip'
food['dairy']['cheese'] == 'Cheddar' 

などと

fruit['red'] == 'Cherry'

ここで、「果物」辞書を「食品」辞書に完全に追加して、次のようにします。

food['fruit']['red'] == 'Cherry'

私はこのようなことができることを知っています:

food['fruit'] = fruit

しかし、それは不器用なようです。私は次のようなことをしたいと思います

food.Append(fruit)

しかし、それは私が必要とすることをしません。

(変数名から最初の大文字を削除するように編集しました。これは、気を散らすように思われたためです。)

4

6 に答える 6

7

Food['Fruit'] = Fruitは正しく適切な方法です(大文字の名前は別として)

@kindall がコメントで賢明に指摘しているように、同じ辞書を参照する複数の名前が存在する可能性があります。そのため、オブジェクトをその名前にマップし、それをfooddict の新しいキーとして使用する関数を作成できません。

于 2012-06-05T19:34:54.347 に答える
4

私はあなたがやろうとしていることを知っています。Python でDRYを回避しようとしています。悲しいことに、Python や他の多くの言語は、これが非常に苦手です。

ただし、主な問題は、変数の名前とプログラムの値を混在させていることです。これは、多くのプログラミング言語でよくある間違いです。

fruit=...本当にこれをしたい場合は、変数にバインドしたものがその名前を知る必要があります。

  • あなたは、Pythonで「このdictをこの他のdictに移植する」と言おうとしています。
  • Python では、「この dict をこの別の dict に移植し、"Fruit""
  • これを回避する唯一の方法は、"Fruit" という名前が既にどこかに存在することです。しかし、そうではありません。変数名にのみ存在し、プログラムにはありません。

次の 2 つの解決策があります。

  • 変数を作成することを避け、代わりに名前fruit=...だけを直接移植することができます。"Fruit"したがって、"Fruit" と入力する必要があるのは 1 回だけですが、必要に応じて入力しない代わりにsomedict["Fruit"]、変数名を入力することを避けています。これは、匿名スタイルでプログラミングすることによって実現されます。

    somedict["Fruit"] = {'red':'apple', 'yellow':'banana'}
    

残念ながら、構築にステートメントが必要な場合、Python ではこれを行うことができません。リテラルしかない場合にのみ、これを回避できます。他の解決策は次のとおりです。

  • これを行う関数を作成できます。

    graft(somedict, "Fruit", {'red':'apple', 'yellow':'banana'})
    

悲しいことに、これも、構造に何らかのステートメントが必要な場合は機能しません。変数x={'red':...}などを作成することもできますが、それでは目的全体が無効になります。使用すべきではない 3 番目の方法は ですlocals()が、それでも名前を参照する必要があります。

fruit=...結論として、IF には重要な for ループと関数、および if ステートメントが必要です。辞書を作成する方法全体を変更しない限り、Python では何をしようとしているかは不可能です。dict((k,v) for k,v in ...)複数行のラムダ、辞書内包表記 ( )、 inlineなどの組み合わせで可能IFTRUE if EXPR else IFFALSEです。このスタイルの危険性は、すぐに読みにくくなることです。

辞書をリテラル辞書、辞書内包表記、または既に記述した関数の出力として表現できる場合は可能です。実際、それはかなり簡単です(他の回答を参照)。残念ながら、元の質問では、これらの辞書をどのように構築しているかはわかりません。

これらの回答があなたの質問に答えないと仮定すると (つまり、これらを非常に複雑な方法で作成している場合)、「メタ」コードを書くことができます。つまり、辞書を作成し、リフレクションを悪用するコードです。ただし、Python での最善の解決策は、反復して辞書を作成することです。例えば:

foods = {
    "Fruit": {...},
    "Meats": makeMeats(),
}
for name,data in ...:
    foods[name] = someProcessing(data)
foods.update(dataFromSomeFile)  #almost same as last two lines
于 2012-06-05T19:53:54.327 に答える
2

角括弧を使用している理由はありますか? このデータ構造は、ネストされたリテラル辞書で表すことができるため、次のようになります。

food = {
    'veg': {
        'red': 'tomato',
        'green': 'lettuce',
    },

    'fruit': {
        'red': 'cherry',
        'green': 'grape',
    },
}
于 2012-06-05T19:39:52.113 に答える
1

あなたが抱えている基本的な問題は、あなたの辞書がそれ自身の名前を知らないということです. これは正常です。一般に、任意の数の名前を 1 つの Python オブジェクトにバインドすることができ、単一の名前が他の名前よりも優先されることは決してありません。つまり、 では、とはa = {}; b = aどちらも同じ辞書の名前であり、最初に割り当てられたという理由だけで、辞書の「実際の」名前ではありません。実際、辞書は、変数の左側にある名前を知る方法さえありません。aba

したがって、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 で実行できる方法です。

于 2012-06-05T21:35:13.683 に答える
1

辞書はリストではないため、追加できません。順序がありません。やりたいことは、新しいキーと値のペアで辞書を更新することです。以下を使用する必要があります。

Food['Fruit'] = Fruit

または、代わりに:

Food.update({'Fruit': Fruit})

無関係な注意: 変数を大文字で記述するのは Python コーディング スタイルではありません。Fruitのように書かれfruitます。

于 2012-06-05T19:35:57.503 に答える
0

あなたはおそらく defaultdict を探しています。新しい最初のレベルのタイプを要求するたびに、新しい空の辞書を追加することで機能します。以下に例を示します。

from collections import defaultdict

basic_foods = {'Veg' : {'Root' : 'Turnip'}, 'Dairy' : {'Cheese' : 'Cheddar'}}

foods = defaultdict(dict, basic_foods)
foods['Fruit']['Red'] = "Cherry"
print foods['Fruit']
于 2012-06-05T19:40:43.187 に答える