74

파이썬에서 사전으로부터 객체를 생성하는 것이 가능한가요? 각 키는 객체의 속성입니다.

이 같은:

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

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

나는 이것이이 질문의 반대가 될 것이라고 생각한다.객체 필드의 파이썬 사전


  • 사이드 발언 :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)예를 들어 "e = Employee (name = ' Oscar ')"와 같은 키워드 인수를 사용할 수있는 init 메소드를 사용하거나 사전 (예 : " e = Employee (** dict) "). - Brent Writes Code
  • 모두 제공Employee(some_dict)그리고Employee(**some_dict)API가 일치하지 않습니다. 어느 쪽이든 더 나은 것이 공급되어야합니다. - Mike Graham
  • arg의 기본값을로 설정하면()대신에None, 당신은 그렇게 할 수 있습니다.def __init__(self, iterable=(), **kwargs): self.__dict__.update(iterable, **kwargs). - Matt Anderson
  • 나는 그것이 오래된 질문이라는 것을 알고 있지만, 단지 목록 이해력을 가진 두 줄에서 할 수 있다고 덧붙이고 싶다. 예를 들면 다음과 같다.[[setattr(self,key,d[key]) for key in d] for d in some_dict] - T.Z.
  • 나는 왜 이것이 파이썬에 내장되어 있지 않은지를 알고 싶다. 이 기능을 사용하여 Python GeoIP2 API를 처리하는 데 사용하고 있습니다.AddressNotFoundError(이 경우 수정 된 데이터를 반환하기보다는 오히려 폭파하지 말 것) - PHP에서 매우 쉽다는 것을 알았습니다 ((object) ['x' => 'y']) 파이썬에서 너무 많은 벼락치기가 필요함 - 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. 당신은 모든 분야가 사전에 있어야하는 것을 모른다. 이 경우 개체 네임 스페이스를 오염시키는 대신 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의 대답을보십시오.


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
  • 나는였다주어진 파이썬 구현에 존재한다는 보장은 없지만, langref에서는 여러 번 언급됩니다. 이안 (Ian)의 대답은 다른 우려 사항을 다루고 있습니다. 즉, 문제를 clobbering하는 대신 설명 자로 전달합니다. - Ignacio Vazquez-Abrams
  • __dict__언어의 문서화 된 부분이지 구현 인공물이 아닙니다. - Dave Kirby
  • 사용setattr액세스하는 것이 바람직합니다.__dict__직접. 당신은 많은 것을 염두에 두어야합니다.__dict__거기에 있지 않거나 사용하지 않을 때 원하는 것을하지 않는 것__dict__, 그러나setattr실제로하는 것과 실질적으로 동일하다.foo.bar = baz. - Mike Graham

6

나는 그 답변을 사용하여 생각settattr당신이 정말로 지원해야하는 경우 갈 길입니다.dict.

하지만Employee객체는 도트 구문을 사용하여 액세스 할 수있는 구조입니다 (.name) 대신 dict 구문 (['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()메서드로 사전에 모든 속성에 액세스 할 수 있지만~ 할 수 없다.추가 속성은 나중에 건설 중에 만 추가하십시오.


  • 속성을 '속성'이라고 지칭하는 것이 가장 좋습니다. 왜냐하면 후자의 용어는 당신이 사용하는 것과 혼동 될 수 있기 때문에 "속성들"보다는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)

또는 속성 오류를 발생시키는 대신 알 수없는 값에 대해 없음을 리턴 할 수 있습니다. (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

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'

연결된 질문


관련된 질문

최근 질문