Pythonで辞書から属性を設定する


102

各キーがそのオブジェクトの属性になるような方法で、Pythonのディクショナリからオブジェクトを作成することは可能ですか?

このようなもの:

 d = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }

 e = Employee(d) 
 print e.name # Oscar 
 print e.age + 10 # 42 

私はそれがこの質問のほぼ逆になると思います:オブジェクトのフィールドからのPython辞書

回答:


172

確かに、このようなもの:

class Employee(object):
    def __init__(self, initial_data):
        for key in initial_data:
            setattr(self, key, initial_data[key])

更新

ブレントナッシュが示唆するように、キーワード引数も許可することで、これをより柔軟にすることができます。

class Employee(object):
    def __init__(self, *initial_data, **kwargs):
        for dictionary in initial_data:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])

次に、次のように呼び出すことができます。

e = Employee({"name": "abc", "age": 32})

またはこのように:

e = Employee(name="abc", age=32)

またはこのようにさえ:

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)

4
あなたが最初のデータを渡すかのようにdef __init__(self,**initial_data)、あなたは(あまりにも(例えば「E =会社員(名= 『オスカー』)」または単に(辞書に取る例えば「E =従業員をキーワード引数を行うことができますinitメソッドを持つの追加利益を得ます**辞書)」)。
ブレントは、コードの書き込み

2
Employee(some_dict)Employee(**some_dict)APIの両方を提供することは矛盾しています。どちらが良いかを指定する必要があります。
マイクグラハム

4
argのデフォルトをの()代わりに設定した場合、次のように設定Noneできますdef __init__(self, iterable=(), **kwargs): self.__dict__.update(iterable, **kwargs)
Matt Anderson、

4
私はそれが古い質問ですけど、私はちょうどそれが例えば、リスト内包して2行で行うことができることを追加したい:[[setattr(self,key,d[key]) for key in d] for d in some_dict]
TZ

2
なぜこれが簡単な方法でpythonに組み込まれていないのか知りたいです。私はこれを使ってpython GeoIP2 APIスローAddressNotFoundError(爆破するのではなく、修正されたデータを返すため)に対処しています-PHP ((object) ['x' => 'y'])で非常に簡単なものはPythonで非常に
粗末

46

この方法で属性を設定することは、ほとんどの場合、問題を解決するための最良の方法ではありません。どちらか:

  1. すべてのフィールドを事前に知っておく必要があります。その場合、すべての属性を明示的に設定できます。これは次のようになります

    class Employee(object):
        def __init__(self, name, last_name, age):
            self.name = name
            self.last_name = last_name
            self.age = age
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(**d) 
    
    print e.name # Oscar 
    print e.age + 10 # 42 

    または

  2. すべてのフィールドが事前にどうあるべきか分からない。この場合、オブジェクトの名前空間を汚染するのではなく、dictとしてデータを保存する必要があります。属性は静的アクセス用です。このケースは次のようになります

    class Employee(object):
        def __init__(self, data):
            self.data = data
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(d) 
    
    print e.data['name'] # Oscar 
    print e.data['age'] + 10 # 42 

基本的にケース1と同等の別の解決策は、を使用することcollections.namedtupleです。それを実装する方法については、vanの回答を参照してください。


そして、シナリオが両極端の間にある場合はどうでしょうか?それはまさにこれのユースケースであり、現在AFAICTはこれをDRYおよびpythonicの方法で行う方法はありません。
DylanYoung

14

を使用してオブジェクトの属性にアクセスし、そのオブジェクト__dict__のupdateメソッドを呼び出すことができます。

>>> class Employee(object):
...     def __init__(self, _dict):
...         self.__dict__.update(_dict)
... 


>>> dict = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }

>>> e = Employee(dict)

>>> e.name
'Oscar'

>>> e.age
32

3
__dict__実装のアーティファクトであり、使用しないでください。また、これはクラス上の記述子の存在を無視します。
Ignacio Vazquez-Abrams

1
@Ignacio「実装アーティファクト」とはどういう意味ですか?気づいてはいけないことは?それとも、異なるプラットフォームに存在しない可能性がありますか?(例:WindowsのPythonとLinuxのPythonの比較)許容できる答えは何ですか?
OscarRyz 2010年

12
__dict__言語の文書化された部分であり、実装の成果物ではありません。
Dave Kirby

3
直接setattrアクセス__dict__するよりも使用することをお勧めします。__dict__使用したときにそこにない、または望んでいることをしていないことにつながる可能性のある多くのことを覚えておく必要がありますが__dict__setattr実際には実際に行っていることと同じですfoo.bar = baz
マイクグラハム

1
@DaveKirby:の一般的な使用__dict__は推奨されないようです:docs.python.org/tutorial/classes.html#id2
equaeghe

10

辞書のキーとして属性名を使用しないのはなぜですか?

class StructMyDict(dict):

     def __getattr__(self, name):
         try:
             return self[name]
         except KeyError as e:
             raise AttributeError(e)

     def __setattr__(self, name, value):
         self[name] = value

名前付き引数、タプルのリスト、ディクショナリ、または個別の属性割り当てで初期化できます。例:

nautical = StructMyDict(left = "Port", right = "Starboard") # named args

nautical2 = StructMyDict({"left":"Port","right":"Starboard"}) # dictionary

nautical3 = StructMyDict([("left","Port"),("right","Starboard")]) # tuples list

nautical4 = StructMyDict()  # fields TBD
nautical4.left = "Port"
nautical4.right = "Starboard"

for x in [nautical, nautical2, nautical3, nautical4]:
    print "%s <--> %s" % (x.left,x.right)

または、属性エラーを発生させる代わりに、不明な値に対してNoneを返すことができます。(web2pyストレージクラスで使用されるトリック)


7

settattr本当にサポートが必要な場合は、答えを使用するのがよいと思いますdict

しかし、Employeeobjectが.namedict構文(['name'])ではなくドット構文()でアクセスできる構造体である場合、次のような名前付きタプルを使用できます。

from collections import namedtuple

Employee = namedtuple('Employee', 'name age')
e = Employee('noname01', 6)
print e
#>> Employee(name='noname01', age=6)

# create Employee from dictionary
d = {'name': 'noname02', 'age': 7}
e = Employee(**d)
print e
#>> Employee(name='noname02', age=7)
print e._asdict()
#>> {'age': 7, 'name': 'noname02'}

_asdict()すべてのプロパティにディクショナリとしてアクセスする方法はあります、後で追加の属性を追加することはできません。作成中のみです。


6

例えば言う

class A():
    def __init__(self):
        self.x=7
        self.y=8
        self.z="name"

属性を一度に設定したい場合

d = {'x':100,'y':300,'z':"blah"}
a = A()
a.__dict__.update(d)

1
便宜上、キー/値を使用できます:a.__dict__.update(x=100, y=300, z="blah")
simno

1

dictを使用するのと同様に、kwargsを次のように使用できます。

class Person:
   def __init__(self, **kwargs):
       self.properties = kwargs

   def get_property(self, key):
       return self.properties.get(key, None)

   def main():
       timmy = Person(color = 'red')
       print(timmy.get_property('color')) #prints 'red'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.