74

各キーがそのオブジェクトの属性になるようにPythonの辞書からオブジェクトを作成することは可能ですか?

このようなもの:

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

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

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


  • サイドリマーク:dict変数の名ではありません、それはタイプを隠しますdict - van

7 답변


124

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

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

更新

Brent Nashが示唆しているように、キーワード引数を許可することでこれをより柔軟にすることができます。

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)


  • 初期データをdef __init__(self,**initial_data)キーワード引数も使用できるinitメソッド(例:" e = Employee(name ='オスカー">" 39")または辞書に取り込む(例:" e =")という利点があります。従業員(**辞書)")。 - Brent Writes Code
  • 両方を提供するEmployee(some_dict)そしてそのEmployee(**some_dict)APIが矛盾しています。どちらか良い方を指定してください。 - Mike Graham
  • 引数のデフォルトをに設定した場合()の代わりにNoneそう、あなたはそうすることができます:def __init__(self, iterable=(), **kwargs): self.__dict__.update(iterable, **kwargs)。 - Matt Anderson
  • 私はそれが古い質問であることを知っています、しかし私はそれがリスト内包表記で2行で行われることができると付け加えたいだけです、例えば:[[setattr(self,key,d[key]) for key in d] for d in some_dict] - T.Z.
  • なぜこれが簡単な方法でpythonに組み込まれていないのか知りたいのですが。 Python GeoIP2 APIのスローを処理するためにこれを使用していますAddressNotFoundError'(その場合は修正するのではなく、修正したデータを返すために) - PHPでは非常に簡単なことに夢中になっていた((object) ['x' => 'y'])Pythonではそれほど多くのことが必要 - Someguy123

35

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

  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. あなたは、すべてのフィールドが前もって何をすべきかを知りません。この場合、オブジェクトの名前空間を汚染するのではなく、データを辞書として格納する必要があります。属性は静的アクセス用です。この場合は、

    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と基本的に同等のもう1つの解決策は、collections.namedtuple。実装方法についてはvanの回答を参照してください。


12

オブジェクトの属性にアクセスすることができます__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


  • __dict__実装成果物であり、使用しないでください。また、これはクラス上の記述子の存在を無視します。 - Ignacio Vazquez-Abrams
  • @Ignacio"実装成果物"とはどういう意味ですか?意識してはいけないことは何ですか。それとも別のプラットフォームに存在しないかもしれませんか? (例:WindowsのPythonとLinuxのPython)受け入れ可能な答えは何でしょうか。 - OscarRyz
  • だったあるPythonの実装にはそれが存在するという保証はありませんが、langrefでは複数回参照されています。イアンの答えは他の懸念、すなわちそれを駄目にするのではなく記述子に渡すことをカバーしている。 - Ignacio Vazquez-Abrams
  • __dict__実装成果物ではなく、言語の文書化された部分です。 - Dave Kirby
  • を使うsetattrアクセスよりも好ましい__dict__直接。あなたはにつながる可能性があることの多くを心に留めておく必要があります__dict__使用しているときに、そこにいない、または自分が望むことをしていない__dict__しかし、setattr実際に行うことと実質的に同じです。foo.bar = baz。 - Mike Graham

6

その答えを使って考えるsettattrあなたが本当に支援する必要があるなら、行く道はありますdict

しかしEmployeeオブジェクトは、ドットシンタックスでアクセスできる単なる構造体です。.namedictの代わりに()['name'])、あなたが使用することができますnamedtupleこのような:

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()辞書としてすべてのプロパティにアクセスする方法できない後で追加の属性を追加するのは、構築時に限られます。


  • 属性を"属性"として参照するのが最善です。後者の用語は、使用したときに得られるものと混同される可能性があるため、「プロパティ」ではなくproperty。 - Mike Graham
  • 良い点 - 修正 - van

6

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

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ストレージクラスで使われているトリック)


5

例えば言う

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)


  • あなたは便宜上キー/値を使うことができます:a.__dict__.update(x=100, y=300, z="blah") - simno

1

辞書を使うのと同じように、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'

リンクされた質問


関連する質問

最近の質問