점 "."을 사용하는 방법 사전 멤버에게 액세스하려면?


283

점 "."을 통해 Python 사전 멤버에 액세스 할 수있게하려면 어떻게해야합니까?

예를 들어을 쓰는 대신을 쓰고 mydict['val']싶습니다 mydict.val.

또한이 방법으로 중첩 된 dicts에 액세스하고 싶습니다. 예를 들어

mydict.mydict2.val 

참조 할 것이다

mydict = { 'mydict2': { 'val': ... } }

20
사람들이 중첩 된 dicts를 사용하는 많은 상황은 튜플을 키로 사용하여 dicts로 d[a][b][c]대체 되거나 더 잘 제공 됩니다 d[a, b, c].
— Mike Graham

7
마술이 아닙니다 : foo = {}; foo [1,2,3] = "하나, 둘, 셋!"; foo.keys () => [(1,2,3)]
— Bryan Oakley

10
와. 또 와우 나는 튜플이 dict의 열쇠가 될 수 있다는 것을 몰랐다. 와우 세번째.
— bodacydo

3
"해시 가능한"모든 객체는 dict의 키로 사용될 수 있습니다. 대부분의 불변 개체는 해시 가능하지만 모든 내용이 해시 가능한 경우에만 가능합니다. 코드 d [1, 2, 3]은 ","가 "튜플 연산자 생성"이므로 작동합니다. d [(1, 2, 3)]와 같습니다. 튜플 선언과 관련하여 괄호는 종종 선택 사항입니다.
— Larry Hastings

6
키 자체에 점이있는 경우를 고려 했습니까 {"my.key":"value"}? 또는 키가 "from"과 같은 키워드 일 때? 나는 그것을 두 번 고려했으며 인식 된 이점보다 더 많은 문제와 문제 해결입니다.
— Todor Minakov

답변:


147

방금 만든이 클래스를 사용하여 수행 할 수 있습니다. 이 클래스를 사용하면 Map다른 사전 (json 직렬화 포함) 또는 점 표기법과 같은 객체를 사용할 수 있습니다 . 나는 당신을 도울 수 있도록 노력하겠습니다 :

class Map(dict):
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
    """
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self[k] = v

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

사용 예 :

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
# Or
m['new_key'] = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']

21
Python 3에서 작업 .iteritems()하기 위해.items()
— berto

13
이것은 AttributeError속성이 존재하지 않으면 증가하지 않는다는 점에서 일반적인 기대와 다르게 작동 합니다. 대신 반환 None됩니다.
— mic_e

딥 카피 및 기타 시스템에서 지원할 수 있도록 getstate 및 setstate를 추가 하는 것이 좋습니다.
— user1363990

4
생성자를로 단순화 할 수 있습니다 self.update(*args,**kwargs). 또한을 추가 할 수 있습니다 __missing__(self,key): value=self[key]= type(self)(); return value. 그런 다음 점 표기법을 사용하여 누락 된 항목을 추가 할 수 있습니다. 당신이 pickable 싶은 경우에, 당신은 추가 할 수 있습니다 __getstate__와__setstate__
— 젠스 뭉크

1
이것은 hasattr(Map, 'anystring') is true. which means the hasattr would always return True due to overriding __getattr__` 을 만들 것입니다
— Xiao

265

나는 항상 이것을 util 파일에 보관했습니다. 자신의 수업에서 믹스 인으로 사용할 수도 있습니다.

class dotdict(dict):
    """dot.notation access to dictionary attributes"""
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

mydict = {'val':'it works'}
nested_dict = {'val':'nested works too'}
mydict = dotdict(mydict)
mydict.val
# 'it works'

mydict.nested = dotdict(nested_dict)
mydict.nested.val
# 'nested works too'

5
아주 간단한 답변입니다! IPython 작업에서 탭 완성 기능을 사용하기 위해 필요한 사항을 알고 있습니까? 클래스는 __dir __ (self)을 구현해야하지만 어떻게 든 작동 할 수는 없습니다.
— andreas-h

8
단순화를 위해 +1 그러나 중첩 된 dicts에서는 작동하지 않는 것 같습니다. d = {'foo': {'bar': 'baz'}}; d = dotdict(d); d.foo.bar속성 오류가 발생하지만 d.foo정상적으로 작동합니다.
— tmthyjames

2
그러나 이것은 복잡한 중첩 구조에서는 작동하지 않습니다.
— David

16
@tmthyjames 간단히 getter 메소드에서 dotdict 유형 객체를 반환하여 다음과 같은 점 표기법으로 속성에 재귀 적으로 액세스 할 수 있습니다. python class DotDict(dict): """dot.notation access to dictionary attributes""" def __getattr__(*args): val = dict.get(*args) return DotDict(val) if type(val) is dict else val __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__
— TMKasun

4
그것을 실험 한 후에, 그것은 누락 된 아이템에 대한 에러를 발생시키는 대신에 get돌아올 것이기 때문에 실제로 나쁜 생각 인 것 같습니다 None...
— NichtJens

117

dotmap통해 설치pip

pip install dotmap

원하는 모든 작업과 하위 클래스를 수행 dict하므로 일반 사전처럼 작동합니다.

from dotmap import DotMap

m = DotMap()
m.hello = 'world'
m.hello
m.hello += '!'
# m.hello and m['hello'] now both return 'world!'
m.val = 5
m.val2 = 'Sam'

또한 dict객체 와 객체 간에 변환 할 수 있습니다 .

d = m.toDict()
m = DotMap(d) # automatic conversion in constructor

즉, 액세스하려는 항목이 이미 dict양식에 들어 있으면 DotMap쉽게 액세스 할 수 있도록 할 수 있습니다.

import json
jsonDict = json.loads(text)
data = DotMap(jsonDict)
print data.location.city

마지막으로 DotMap다음과 같은 작업을 수행 할 수 있도록 자동으로 새 자식 인스턴스를 만듭니다 .

m = DotMap()
m.people.steve.age = 31

무리와 비교

전체 공개 : 저는 DotMap 의 제작자입니다 . Bunch이 기능이 없어서 만들었습니다.

  • 주문 항목을 기억하고 그 순서대로 반복
  • 자동 하위 DotMap생성 기능을 통해 시간이 절약되고 계층 구조가 많을 때 코드가 깨끗해집니다.
  • 에서 dict모든 자식 dict인스턴스를 생성 하고 재귀 적으로 변환DotMap

2
:-) 이름에 이미 점이있는 키로 작동하게 할 수 있습니까? 그것은 환상적인 것입니다 {"test.foo": "bar"}통해 통해 액세스 할 수 있습니다 mymap.test.foo. 플랫 맵을 깊은 맵으로 변환 한 다음 DotMap을 적용하려면 약간의 회귀가 필요하지만 그만한 가치가 있습니다!
— dlite922

산뜻한. Jupyter 노트북의 키로 탭 목록 / 완료 작업을 수행하는 방법은 무엇입니까? 도트 스타일 액세스는 대화식 사용에 가장 유용합니다.
— Dmitri

@Dmitri Cool 제품. 전에는 들어 본 적이 없으므로 자동 완성 작업을 수행하는 방법을 모르겠습니다. DotMap자동 완성 기능을 사용 하는 것이 가장 좋습니다. 이전에 입력 한 키워드를 자동 완성하는 Sublime Text를 사용합니다.
— Chris Redford

1
**kwargs또는 과 같은 것들에 대한 사전 추출이 부족하다는 것을 알았습니다 c = {**a, **b}. 실제로, 그것은 조용히 실패하고, 추출 할 때 빈 사전처럼 행동합니다.
— Simon Streicher

@SimonStreicher 나는 이것을 테스트 m = DotMap(); m.a = 2; m.b = 3; print('{a} {b}'.format(**m));하고 예상했다 2 3. 작동 dict()하지만 DotMap()문제가 해결 되지 않은 입증 된 사례가있는 경우 코드를 GitHub의 이슈 탭에 제출하십시오.
— Chris Redford

56

받아쓰기 및 구현 __getattr__및 __setattr__.

또는 매우 유사한 Bunch 를 사용할 수 있습니다 .

내장 dict 클래스를 monkeypatch하는 것이 가능하지 않다고 생각합니다.


2
monkeypatch는 정확히 무엇을 의미합니까? 나는 그것에 대해 들었지만 사용하지 않았습니다. (죄송합니다 제가 아직 프로그래밍과 좋은 (난 단지 2 학년 학생입니다하지 않는 것이 오전 같은 초보자 질문을하는 것이).)
— bodacydo

9
몽키 패칭은 파이썬 (또는 다른 언어)의 동 적성을 사용하여 일반적으로 소스 코드에서 정의되는 것을 변경합니다. 클래스가 작성된 후 클래스 정의를 변경하는 데 특히 적용됩니다.
— Mike Graham

이 기능을 많이 사용한다면 번치 속도에주의하십시오. 나는 그것을 자주 사용하고 있었고 요청 시간의 3 분의 1을 소비했습니다. 이에 대한 자세한 설명은 내 답변을 확인하십시오.
— JayD3e

22

패브릭 은 정말 훌륭하고 최소한의 구현을 가지고 있습니다. 중첩 액세스를 허용하도록 확장하면을 사용할 수 defaultdict있으며 결과는 다음과 같습니다.

from collections import defaultdict

class AttributeDict(defaultdict):
    def __init__(self):
        super(AttributeDict, self).__init__(AttributeDict)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(key)

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

다음과 같이 사용하십시오.

keys = AttributeDict()
keys.abc.xyz.x = 123
keys.abc.xyz.a.b.c = 234

이는 Kugel의 "dict and and implementation __getattr__and from and dict"에__setattr__ 대한 답변을 조금 더 자세하게 설명합니다 . 이제 당신은 방법을 알고 있습니다!


1
그거 대단해!
— 토마스 클링 거

defaultdict를 포함시키는 것이 좋지만 dict는 처음부터 dict를 시작할 때만 작동하는 것 같습니다. 기존 dict을 재귀 적으로 "dotdict"로 변환해야하는 경우 다음은 dotdict기존 dict객체를 재귀 적 으로 변환 할 수 있는 대안 입니다 . gist.github.com/miku/…
— miku

19

나는 이것을 시도했다 :

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

당신도 시도 할 수 __getattribute__있습니다.

모든 dict을 dotdict의 유형으로 충분하게 만드십시오. 멀티 레이어 dict에서 이것을 시작하려면 구현하십시오 __init__.


@Kugel의 대답은 비슷합니다.
— tdihp

1
tdihp, 나는 더 빨리 이해했기 때문에 당신의 대답을 여전히 좋아합니다. 실제 코드가 있습니다.
— yigal

1
실제 코드는 +1입니다. 그러나 @Kugel의 Bunch 사용 제안도 매우 좋습니다.
— Dannid

나는 그것이 유용하게 배치하여 함수 내에서이를 포함하는 것으로 def docdict(name):`다음 이전과 isinstance (이름, DICT)의 경우 : 반환 DotDict (이름) 반환 이름`
— 다니엘 Moskovich

훌륭한 간단한 예제 .. @DanielMoskovich와 유사하게 중첩 된 dict가 쉽게 연결되도록 int, string 등에 대해 리프 노드를 올바르게 반환하거나 찾을 수없는 경우 null을 반환합니다.class dotdict(dict): def __getattr__(self, name): if name not in self: return None elif type(self[name]) is dict: return JsonDot(self[name]) else: return self[name]
— D Sievers

11

하지마 파이썬에서 속성 접근과 색인 생성은 별개의 것이므로, 그것들이 같은 것을 수행해서는 안됩니다. namedtuple접근 가능한 속성을 가져야 할 []항목이 있고 표기법을 사용 하여 dict에서 항목을 가져 오는 경우 클래스를 만들 수 있습니다 (아마 만든 클래스 ) .


답변 해주셔서 감사합니다. 그러나 방금 질문 한이 질문을 살펴보십시오. stackoverflow.com/questions/2352252/… 이것은 Mako 템플릿의 복잡한 데이터 구조에 액세스 하는 .대신 사용하는 것이 좋습니다 [].
— bodacydo 2019

2
이에 대한 사용 사례를 볼 수 있습니다. 사실, 나는 몇 주 전에 그 일을했습니다. 필자의 경우 점 표기법으로 속성에 액세스 할 수있는 객체를 원했습니다. 모든 dict 기능이 내장되어 있으므로 dict에서 상속하는 것이 매우 쉽다는 것을 알았지만이 객체에 대한 공용 인터페이스는 점 표기법을 사용합니다 (기본적으로 정적 데이터에 대한 읽기 전용 인터페이스입니다). 내 사용자는 'foo [ "bar"]'보다 'foo.bar'에 훨씬 만족하며 dict 데이터 유형의 기능을 피기 백 할 수있어서 기쁩니다.
— Bryan Oakley

10
당신은 이미 좋은 파이썬 스타일을 알고 있습니다 : 우리는 당신에게 말하고 있습니다, dict의 값이 속성이라고 가정하지 마십시오. 나쁜 습관입니다. 예를 들어, "항목"또는 "get"또는 "pop"과 같은 dict의 기존 속성과 이름이 같은 값을 저장하려면 어떻게해야합니까? 아마 혼란스러운 것입니다. 그러지 마!
— Larry Hastings

5
'항목', 'get'또는 'pop'과 같은 속성을 잊었습니다. 이 중요한 예를 제시해 주셔서 감사합니다!
— bodacydo

5
@Gabe, 오랜 시간이 지났지 만 말할 가치가 있다고 생각합니다. "JS에서는 충분하지 않다": "JS에서는 끔찍하다". 프로토 타입 체인의 다른 중요한 속성과 이름이 같은 키 / attr을 저장하면 재미 있습니다.
— bgusach

11

수정 된 사전을 피클 링하려면 위의 답변에 몇 가지 상태 메소드를 추가해야합니다.

class DotDict(dict):
    """dot.notation access to dictionary attributes"""
    def __getattr__(self, attr):
        return self.get(attr)
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

    def __getstate__(self):
        return self

    def __setstate__(self, state):
        self.update(state)
        self.__dict__ = self

산세에 대한 의견에 감사드립니다. 나는이 오류에 미치게 되었고이 문제로 인한 것임을 깨달았습니다!
— Shagru

copy.deepcopy를 사용할 때도 발생합니다. 이 추가가 필요합니다.
— user1363990

단순화 :__getattr__ = dict.get
— 마르티노

9

Kugel의 답변을 바탕으로 Mike Graham의주의 사항을 고려하면 래퍼를 만들면 어떨까요?

class DictWrap(object):
  """ Wrap an existing dict, or create a new one, and access with either dot 
    notation or key lookup.

    The attribute _data is reserved and stores the underlying dictionary.
    When using the += operator with create=True, the empty nested dict is 
    replaced with the operand, effectively creating a default dictionary
    of mixed types.

    args:
      d({}): Existing dict to wrap, an empty dict is created by default
      create(True): Create an empty, nested dict instead of raising a KeyError

    example:
      >>>dw = DictWrap({'pp':3})
      >>>dw.a.b += 2
      >>>dw.a.b += 2
      >>>dw.a['c'] += 'Hello'
      >>>dw.a['c'] += ' World'
      >>>dw.a.d
      >>>print dw._data
      {'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3}

  """

  def __init__(self, d=None, create=True):
    if d is None:
      d = {}
    supr = super(DictWrap, self)  
    supr.__setattr__('_data', d)
    supr.__setattr__('__create', create)

  def __getattr__(self, name):
    try:
      value = self._data[name]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[name] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

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

  def __getitem__(self, key):
    try:
      value = self._data[key]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[key] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setitem__(self, key, value):
    self._data[key] = value

  def __iadd__(self, other):
    if self._data:
      raise TypeError("A Nested dict will only be replaced if it's empty")
    else:
      return other


6

나는 Munch를 좋아하고 도트 액세스 위에 많은 편리한 옵션을 제공합니다.

수입 뭉크

temp_1 = { 'person': { 'fname': 'senthil', 'lname': 'ramalingam'}}

dict_munch = munch.munchify (temp_1)

dict_munch.person.fname


6

나는 최근에 ' 상자를 발견했다 에 같은 일 '라이브러리를 발견했습니다.

설치 명령 : pip install python-box

예:

from box import Box

mydict = {"key1":{"v1":0.375,
                    "v2":0.625},
          "key2":0.125,
          }
mydict = Box(mydict)

print(mydict.key1.v1)

나는 도트 맵과 같은 다른 기존 라이브러리보다 더 효과적이라는 것을 알았습니다.이 맵은 큰 중첩 dict가있을 때 파이썬 재귀 오류를 생성합니다.

라이브러리 및 세부 사항 링크 : https://pypi.org/project/python-box/


5

__getattr__Python 3.4.3에서 매우 간단한을 사용하십시오 .

class myDict(dict):
    def __getattr__(self,val):
        return self[val]


blockBody=myDict()
blockBody['item1']=10000
blockBody['item2']="StackOverflow"
print(blockBody.item1)
print(blockBody.item2)

산출:

10000
StackOverflow

4

언어 자체는이를 지원하지 않지만 때로는 여전히 유용한 요구 사항입니다. Bunch 레시피 외에도 점선 문자열을 사용하여 사전에 액세스 할 수있는 작은 방법을 작성할 수도 있습니다.

def get_var(input_dict, accessor_string):
    """Gets data from a dictionary using a dotted accessor-string"""
    current_data = input_dict
    for chunk in accessor_string.split('.'):
        current_data = current_data.get(chunk, {})
    return current_data

다음과 같은 것을 지원합니다 :

>> test_dict = {'thing': {'spam': 12, 'foo': {'cheeze': 'bar'}}}
>> output = get_var(test_dict, 'thing.spam.foo.cheeze')
>> print output
'bar'
>>

4

epool의 답변을 바탕 으로이 버전을 사용하면 도트 연산자를 통해 내부의 모든 dict에 액세스 할 수 있습니다.

foo = {
    "bar" : {
        "baz" : [ {"boo" : "hoo"} , {"baba" : "loo"} ]
    }
}

예를 들어을 foo.bar.baz[1].baba반환합니다 "loo".

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    if isinstance(v, dict):
                        v = Map(v)
                    if isinstance(v, list):
                        self.__convert(v)
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                if isinstance(v, dict):
                    v = Map(v)
                elif isinstance(v, list):
                    self.__convert(v)
                self[k] = v

    def __convert(self, v):
        for elem in xrange(0, len(v)):
            if isinstance(v[elem], dict):
                v[elem] = Map(v[elem])
            elif isinstance(v[elem], list):
                self.__convert(v[elem])

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

1
파이썬 3 : 교체 iteritems()로 items()와 xrange()함께range()
— sasawatc

3
def dict_to_object(dick):
    # http://stackoverflow.com/a/1305663/968442

    class Struct:
        def __init__(self, **entries):
            self.__dict__.update(entries)

    return Struct(**dick)

영구적 dict으로 객체 로 변환하기로 결정한 경우 이를 수행해야합니다. 액세스 직전에 버리기 개체를 만들 수 있습니다.

d = dict_to_object(d)

데프 attr (** kwargs) : o = 람다 : 없음 o .__ dict __. update (** kwargs) 반환 o
— throws_exceptions_at_you

2

나는 AttrDict 와 Bunch를 모두 시도했다.라이브러리를 사용하여 느리게 사용하는 것으로 나타났습니다. 친구와 함께 조사한 결과, 이러한 라이브러리를 작성하는 주된 방법은 라이브러리가 중첩 된 객체를 통해 적극적으로 재귀하고 사전 객체의 사본을 작성하는 것으로 나타났습니다. 이를 염두에두고 두 가지 주요 사항을 변경했습니다. 1) 속성을 게으르게로드했습니다. 2) 사전 개체의 복사본을 만드는 대신 경량 프록시 개체의 복사본을 만듭니다. 이것이 최종 구현입니다. 이 코드를 사용하면 성능이 크게 향상됩니다. AttrDict 또는 Bunch를 사용할 때이 두 라이브러리는 각각 내 요청 시간의 1/2과 1/3을 소비했습니다 (무엇!?). 이 코드는 그 시간을 거의 아무것도 (0.5ms 범위) 줄였습니다. 물론 이것은 필요에 따라 다르지만 코드에서이 기능을 사용하고 있다면

class DictProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    def __getattr__(self, key):
        try:
            return wrap(getattr(self.obj, key))
        except AttributeError:
            try:
                return self[key]
            except KeyError:
                raise AttributeError(key)

    # you probably also want to proxy important list properties along like
    # items(), iteritems() and __len__

class ListProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    # you probably also want to proxy important list properties along like
    # __iter__ and __len__

def wrap(value):
    if isinstance(value, dict):
        return DictProxy(value)
    if isinstance(value, (tuple, list)):
        return ListProxy(value)
    return value

원래 구현을 참조하십시오 여기 에서 https://stackoverflow.com/users/704327/michael-merickel .

주목해야 할 또 다른 사항은이 구현이 매우 단순하고 필요한 모든 메소드를 구현하지는 않는다는 것입니다. DictProxy 또는 ListProxy 객체에 필요한대로 작성해야합니다.


0

내 자신의 솔루션을 반지에 넣고 싶습니다.

https://github.com/skorokithakis/jsane

JSON을 액세스 할 수있는 것으로 구문 분석 할 수 있습니다 with.attribute.lookups.like.this.r(). 주로 작업하기 전에이 답변을 보지 못했기 때문입니다.


파이썬은 성가신 단순한 디자인 실수가 거의 없으며, 제기 KeyError는 그 중 하나입니다. 존재하지 않는 키에 액세스 할 때 NoneJS 동작과 비슷한 것을 반환하는 것입니다 . 나는 읽기와 쓰기 모두를위한 자생의 열렬한 팬입니다. 도서관이 가장 이상적입니다.
— nehem

0

OP의 질문에 대한 직접적인 대답은 아니지만 일부 사람들에게 영감을 주었을 것입니다. 내부 __dict__코드를 사용하여 객체 기반 솔루션을 만들었습니다.

payload = {
    "name": "John",
    "location": {
        "lat": 53.12312312,
        "long": 43.21345112
    },
    "numbers": [
        {
            "role": "home",
            "number": "070-12345678"
        },
        {
            "role": "office",
            "number": "070-12345679"
        }
    ]
}


class Map(object):
    """
    Dot style access to object members, access raw values
    with an underscore e.g.

    class Foo(Map):
        def foo(self):
            return self.get('foo') + 'bar'

    obj = Foo(**{'foo': 'foo'})

    obj.foo => 'foobar'
    obj._foo => 'foo'

    """

    def __init__(self, *args, **kwargs):
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self.__dict__[k] = v
                    self.__dict__['_' + k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self.__dict__[k] = v
                self.__dict__['_' + k] = v

    def __getattribute__(self, attr):
        if hasattr(self, 'get_' + attr):
            return object.__getattribute__(self, 'get_' + attr)()
        else:
            return object.__getattribute__(self, attr)

    def get(self, key):
        try:
            return self.__dict__.get('get_' + key)()
        except (AttributeError, TypeError):
            return self.__dict__.get(key)

    def __repr__(self):
        return u"<{name} object>".format(
            name=self.__class__.__name__
        )


class Number(Map):
    def get_role(self):
        return self.get('role')

    def get_number(self):
        return self.get('number')


class Location(Map):
    def get_latitude(self):
        return self.get('lat') + 1

    def get_longitude(self):
        return self.get('long') + 1


class Item(Map):
    def get_name(self):
        return self.get('name') + " Doe"

    def get_location(self):
        return Location(**self.get('location'))

    def get_numbers(self):
        return [Number(**n) for n in self.get('numbers')]


# Tests

obj = Item({'foo': 'bar'}, **payload)

assert type(obj) == Item
assert obj._name == "John"
assert obj.name == "John Doe"
assert type(obj.location) == Location
assert obj.location._lat == 53.12312312
assert obj.location._long == 43.21345112
assert obj.location.latitude == 54.12312312
assert obj.location.longitude == 44.21345112

for n in obj.numbers:
    assert type(n) == Number
    if n.role == 'home':
        assert n.number == "070-12345678"
    if n.role == 'office':
        assert n.number == "070-12345679"

0

도트 액세스 (배열 액세스는 아님)를 얻는 간단한 방법 중 하나는 파이썬에서 일반 객체를 사용하는 것입니다. 이처럼 :

class YourObject:
    def __init__(self, *args, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

... 다음과 같이 사용하십시오.

>>> obj = YourObject(key="value")
>>> print(obj.key)
"value"

... 그것을 dict로 변환하려면 :

>>> print(obj.__dict__)
{"key": "value"}

0

이 솔루션은 일관된 방식으로 중첩 된 dicts에 액세스하기 위해 OP의 요구 사항을 해결하기 위해 epool 이 제공 한 솔루션을 개선 한 것 입니다. epool의 솔루션은 중첩 된 dicts에 액세스 할 수 없었습니다.

class YAMLobj(dict):
    def __init__(self, args):
        super(YAMLobj, self).__init__(args)
        if isinstance(args, dict):
            for k, v in args.iteritems():
                if not isinstance(v, dict):
                    self[k] = v
                else:
                    self.__setattr__(k, YAMLobj(v))


    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(YAMLobj, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(YAMLobj, self).__delitem__(key)
        del self.__dict__[key]

이 클래스를 사용하면 다음과 같은 작업을 수행 할 수 있습니다 A.B.C.D.


0

이것은 또한 중첩 된 dicts와 함께 작동하며 나중에 추가 된 dicts가 동일하게 작동하는지 확인합니다.

class DotDict(dict):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Recursively turn nested dicts into DotDicts
        for key, value in self.items():
            if type(value) is dict:
                self[key] = DotDict(value)

    def __setitem__(self, key, item):
        if type(item) is dict:
            item = DotDict(item)
        super().__setitem__(key, item)

    __setattr__ = __setitem__
    __getattr__ = dict.__getitem__

0

@ derek73의 대답 은 매우 깔끔하지만 피클이나 (깊게) 복사 할 수 없으며 반환됩니다.None 누락 된 키를 합니다. 아래 코드는 이것을 수정합니다.

편집 : 나는 정확히 같은 점을 다루는 위의 답변을 보지 못했습니다 (위로). 나는 대답을 여기에 남겨두고 참조 할 것입니다.

class dotdict(dict):
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

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

-1

섬세한 솔루션 종류

class DotDict(dict):

    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, key):

        def typer(candidate):
            if isinstance(candidate, dict):
                return DotDict(candidate)

            if isinstance(candidate, str):  # iterable but no need to iter
                return candidate

            try:  # other iterable are processed as list
                return [typer(item) for item in candidate]
            except TypeError:
                return candidate

            return candidate

        return typer(dict.get(self, key))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.