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


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

딥 카피 및 기타 시스템에서 지원할 수 있도록 getstatesetstate를 추가 하는 것이 좋습니다.
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

나는 AttrDictBunch를 모두 시도했다.라이브러리를 사용하여 느리게 사용하는 것으로 나타났습니다. 친구와 함께 조사한 결과, 이러한 라이브러리를 작성하는 주된 방법은 라이브러리가 중첩 된 객체를 통해 적극적으로 재귀하고 사전 객체의 사본을 작성하는 것으로 나타났습니다. 이를 염두에두고 두 가지 주요 사항을 변경했습니다. 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.