82

CSV からインポートして、おおよそ次の形式でデータを取得しています

{ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }

フィールドの名前は動的です。(まあ、それらは Field1 と Field2 以外にも存在する可能性があるという点で動的ですが、私は知ってField1おりField2、常に存在するつもりです。

allMyFields上記のデータにプロパティとしてアクセスできるように、この辞書をクラスに渡すことができるようにしたいと考えています。

class allMyFields:
    # I think I need to include these to allow hinting in Komodo. I think.
    self.Field1 = None
    self.Field2 = None

    def __init__(self,dictionary):
        for k,v in dictionary.items():
            self.k = v
            #of course, this doesn't work. I've ended up doing this instead
            #self.data[k] = v
            #but it's not the way I want to access the data.

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
instance = allMyFields(q)
# Ideally I could do this.
print q.Field1

助言がありますか?なぜかというと、コード ヒンティングを利用できるようにしたいのですが、dataこれまで行ってきたように呼び出された辞書にデータをインポートしても、そのような余裕はありません。

self.Field1 = None(変数名は実行時まで解決されないため、まだ Komodo に骨を投げる必要があります。これで十分だと思います。)

では、どうすればやりたいことができますか? それとも、設計が不十分な Python 以外のツリーを吠えていますか?

4

10 に答える 10

131

使用できますsetattr(ただし、すべての文字列が有効な属性名であるとは限りません!):

>>> class AllMyFields:
...     def __init__(self, dictionary):
...         for k, v in dictionary.items():
...             setattr(self, k, v)
... 
>>> o = AllMyFields({'a': 1, 'b': 2})
>>> o.a
1

編集:上記のコードとSilentGhost の answerの違いを説明させてください。上記のコード スニペットは、指定されたディクショナリに基づくインスタンス属性を持つクラスを作成します。SilentGhost のコードは、指定されたディクショナリに基づくクラス属性を持つクラスを作成します。

特定の状況に応じて、これらのソリューションのいずれかがより適している場合があります。1 つまたは複数のクラス インスタンスを作成しますか? 答えが1つである場合は、オブジェクトの作成を完全にスキップして、タイプのみを構築することもできます(したがって、SilentGhostの答えに進みます)。

于 2009-10-28T18:31:01.150 に答える
40
>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
>>> q = type('allMyFields', (object,), q)
>>> q.Field1
3000

ここで何が起こっているのかをよく説明するためのドキュメントtype(コンストラクタとしての使用を参照)。

edit : インスタンス変数が必要な場合は、以下も機能します。

>>> a = q()             # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1           # second instance
3000
于 2009-10-28T18:32:56.587 に答える
14

dict.update手動でループする代わりに使用することもできitemsます (ループしている場合は、iteritemsより優れています)。

class allMyFields(object):
    # note: you cannot (and don't have to) use self here
    Field1 = None
    Field2 = None

    def __init__(self, dictionary):
        self.__dict__.update(dictionary)

q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
instance = allMyFields(q)

print instance.Field1      # => 3000
print instance.Field2      # => 6000
print instance.RandomField # => 5000
于 2009-10-28T18:37:28.187 に答える
6

dictキーの属性ルックアップを可能にするサブクラスを作成できます。

class AttributeDict(dict):
    def __getattr__(self, name):
        return self[name]

q = AttributeDict({ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 })
print q.Field1              
print q.Field2              
print q.RandomField

dictすでに(saykeysまたはget)を持っている属性を検索しようとすると、そのdictクラス属性(メソッド)を取得します。dict要求したキーがクラスに存在しない場合、__getattr__メソッドが呼び出され、キーの検索が行われます。

于 2009-10-28T19:46:35.613 に答える
5

名前付きタプルの使用 (Python 2.6):

>>> from collections import namedtuple

>>> the_dict = {'Field1': 3, 'Field2': 'b', 'foo': 4.9}
>>> fields = ' '.join(the_dict.keys())
>>> AllMyFields = namedtuple('AllMyFields', fields)
>>> instance = AllMyFields(**the_dict)

>>> print instance.Field1, instance.Field2, instance.foo
3 b 4.9
于 2009-10-28T19:05:09.940 に答える
3

きれいな方法にはsetattrを使用してください。簡単な方法は、インスタンスの内部辞書を更新することです。

>>> class A(object):
...    pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
于 2009-10-28T18:37:31.760 に答える
1

dict のサブクラスの拡張

再発口述が機能します!

class AttributeDict(dict):
    """https://stackoverflow.com/a/1639632/6494418"""

    def __getattr__(self, name):
        return self[name] if not isinstance(self[name], dict) \
            else AttributeDict(self[name])


if __name__ == '__main__':
    d = {"hello": 1, "world": 2, "cat": {"dog": 5}}
    d = AttributeDict(d)
    print(d.cat)
    print(d.cat.dog)
    print(d.cat.items())

    """
    {'dog': 5}
    5
    dict_items([('dog', 5)])
    """
于 2019-07-25T18:34:36.193 に答える