programing

속성처럼 dict 키에 액세스하시겠습니까?

kingscode 2022. 9. 8. 23:04
반응형

속성처럼 dict 키에 액세스하시겠습니까?

는 'dict'로 합니다.obj.fooobj['foo']그래서 이렇게 썼어요.

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __setattr__(self, attr, value):
        self[attr] = value

하지만 Python이 이 기능을 바로 제공하지 않는 이유가 있을 것이라고 생각합니다.이 방법으로 dict 키에 액세스 할 때의 주의사항과 함정은 무엇입니까?

업데이트 - 2020

거의 10년 전에 이 질문을 한 이후로 Python 자체에서 상당한 변화가 있었다.

내 원래 답변의 접근방식은 여전히 일부 케이스(예: 오래된 버전의 Python을 고수하는 레거시 프로젝트 및 매우 역동적인 문자열 키로 사전을 처리해야 하는 경우)에 유효하지만, 일반적으로 Python 3.7에 도입된 데이터클래스는 대부분의 사용 사례에 대한 명백한/올바른 솔루션이라고 생각한다.AttrDict.

원답

이를 위한 최선의 방법은 다음과 같습니다.

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

장점:

  • 정말 효과가 있어요!
  • 처리되어 있지 예: 「」 「」 「」 「」)..keys()정상적으로 동작합니다.물론 일부 가치를 할당하지 않는 한 아래를 참조해 주십시오.
  • 속성과 항목은 항상 동기화됩니다.
  • 하지 않는 하면, 「」가 발생합니다.AttributeErrorKeyError
  • [Tab] 자동 완성 지원(예: 주피터 및 ipython)

단점:

  • 음음음 methods methods .keys()수신 데이터에 의해 덮어쓰면 정상적으로 동작하지 않습니다.
  • Python < 2 . 7 . 4 / Python 3 < 3.2 . 3 python leak메모리 누설이 발생합니다.
  • E1123(unexpected-keyword-arg) ★★★★★★★★★★★★★★★★★」E1103(maybe-no-member)
  • 초보자에게 그것은 순수한 마술처럼 보인다.

이 기능의 간단한 설명

  • 으로 python이라는 합니다.__dict__.
  • 에 꼭 .__dict__' 받아쓰기해야 하기 할 수 .dict()내부 사전으로 이동합니다.
  • '어울리다'를 붙입니다.AttrDict()있는 (「」에 그대로)__init__를 참조해 주세요.
  • 「 」를 합니다.super()의 »__init__()이 함수가 모든 사전 인스턴스화 코드를 호출하기 때문에, 우리는 그것이 사전과 똑같이 동작하는지 확인했습니다.

Python이 이 기능을 바로 제공하지 않는 이유 중 하나

「cons」목록에 기재되어 있듯이, 이것은 저장된 키의 네임스페이스(임의의 데이터나 신뢰할 수 없는 데이터로부터 얻을 수 있는!)와 내장된 dict 메서드 속성의 네임스페이스를 결합합니다.예를 들어 다음과 같습니다.

d = AttrDict()
d.update({'items':["jacket", "necktie", "trousers"]})
for k, v in d.items():    # TypeError: 'list' object is not callable
    print "Never reached!"

배열 표기법을 사용하는 경우 모든 유효한 문자열 문자를 키의 일부로 지정할 수 있습니다.를 들어, 「」라고 하는 것은,obj['!#$%^&*()_']

질문받은 질문에 답하다

왜 Python은 즉시 그것을 제공하지 않는가?

저는 이것이 파이썬의 젠과 관련이 있다고 생각합니다. "명백한 방법은 하나, 그리고 가급적 하나뿐이어야 합니다."이를 통해 사전에서 값에 액세스하는 두 가지 분명한 방법이 생성됩니다.obj['key'] ★★★★★★★★★★★★★★★★★」obj.key.

경고 및 함정

여기에는 코드의 명확성 결여나 혼동을 생각할 수 있습니다.예를 들어, 나중에 코드를 유지하려고 하는 다른 사용자나, 잠시 동안 코드를 다시 사용하지 않을 경우 사용자에게 혼란을 줄 수 있습니다.다시 Zen에서 "가독성이 중요합니다!"

>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1

ifd인스턴스화 또는 KEY정의되어 있거나 d[KEY]에서 멀리 떨어진 곳에 할당되어 있습니다.d.spam사용되고 있기 때문에, 이것은 일반적으로 사용되는 관용어가 아니기 때문에, 행해지고 있는 것에 대한 혼란으로 이어질 수 있습니다.게게는는는는는는는는는는는는는는는는는는

「」의 을 .KEY, 변경 )d.spam 하면 과 같은 내용이 나옵니다

>>> KEY = 'foo'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: 'C' object has no attribute 'spam'

IMO, 노력 할 가치가 없어.

기타 항목

다른 사용자가 지적한 바와 같이 해시 가능한 객체(문자열뿐 아니라)를 딕트 키로 사용할 수 있습니다.예를들면,

>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>> 

합법이지만

>>> C = type('C', (object,), {(2, 3): True})
>>> d = C()
>>> assert d.(2, 3) is True
  File "<stdin>", line 1
  d.(2, 3)
    ^
SyntaxError: invalid syntax
>>> getattr(d, (2, 3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
>>> 

그렇지 않습니다. 이렇게 하면 개체 속성에 액세스할 때 가지고 있지 않은 사전 키의 인쇄 가능한 문자 또는 기타 해시 가능한 개체에 대한 전체 범위에 액세스할 수 있습니다.이것에 의해, Python Cookbook(Ch. 9)의 레시피와 같이, 캐시된 오브젝트 메타클래스등의 마법을 가능하게 합니다.

내가 편집하는 곳

이 더 좋아요.spam.eggs에 걸쳐서spam['eggs'](깨끗해 보인다고 생각합니다)를 만났을 때 이 기능을 매우 갈망하게 되었습니다만, 이하의 조작이 가능한 편리함이 우선입니다.

>>> KEYS = 'spam eggs ham'
>>> VALS = [1, 2, 3]
>>> d = {k: v for k, v in zip(KEYS.split(' '), VALS)}
>>> assert d == {'spam': 1, 'eggs': 2, 'ham': 3}
>>>

예이지만,는 자주 제가 하고 있는 하게 됩니다.obj.key「」(XMLPrefs」) 「」) 심미적인 하고, 를 붙이고 가독성을 , 딕트를 합니다.다른 경우에는, 심미적인 이유로 동적 클래스를 인스턴스화하고 속성을 붙이고 싶을 때, 읽기 쉽게 하기 위해 일관성을 위한 dict를 계속 사용합니다.

OP는 오래전에 이 문제를 만족스럽게 해결했다고 생각합니다만, 그래도 이 기능을 원하신다면 pypi에서 패키지를 다운로드해 보시기 바랍니다.

  • 번치가 내가 더 잘 아는 사람이야.서브클래스dict이치노
  • AttrDict도 꽤 좋은 것처럼 보이지만, 저는 Bunch만큼 잘 알지 못하고 출처를 자세히 살펴보지도 않았습니다.
  • 중독자는 적극적으로 유지되며 애트리뷰트 같은 접근 및 기타 기능을 제공합니다.
  • Rotareti의 댓글에서 알 수 있듯이 Bunch는 폐지되었지만 Munch라는 액티브 포크가 있다.

단, 코드의 가독성을 높이기 위해 표기법을 혼용하지 말 것을 강력히 권장합니다.이 표기법을 사용할 경우 동적 객체를 인스턴스화하고 원하는 속성을 추가한 후 다음 작업을 종료해야 합니다.

>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}


업데이트 시 댓글의 후속 질문에 답변하기 위해

코멘트(아래)에서 Elmo는 다음과 같이 질문합니다.

좀 더 깊이 들어가고 싶다면요?(타입(...)을 참조).

사용 한 적이 없지만,는 네스트된 사용 를 사용하는 이 있습니다. '네스트된' '네스트된' '네스트된' '네스트된' '네스트된' '네스트된' '네스트된' '네스트된' '네스트된' '네스트된' '네스트'를 사용하는 입니다.dict하기 위해서)의는 다음과 같습니다 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .

>>> C = type('C', (object,), {})
>>> d = C()
>>> for x in 'spam eggs ham'.split():
...     setattr(d, x, C())
...     i = 1
...     for y in 'one two three'.split():
...         setattr(getattr(d, x), y, i)
...         i += 1
...
>>> assert d.spam.__dict__ == {'one': 1, 'two': 2, 'three': 3}

이 기타 SO 질문에는 기존 코드를 단순화하는 훌륭한 구현 예가 있습니다.그럼 어떻게 해?

class AttributeDict(dict):
    __slots__ = () 
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__

하게, 더 __getattr__ ★★★★★★★★★★★★★★★★★」__setattr__기능을 합니다.

표준 라이브러리에서 편리한 컨테이너 클래스를 가져올 수 있습니다.

from argparse import Namespace

코드 비트를 복사하지 않아도 됩니다.표준 사전 접근은 없지만, 원한다면 쉽게 찾을 수 있습니다.argparse의 코드는 간단합니다.

class Namespace(_AttributeHolder):
    """Simple object for storing attributes.

    Implements equality by attribute names and values, and provides a simple
    string representation.
    """

    def __init__(self, **kwargs):
        for name in kwargs:
            setattr(self, name, kwargs[name])

    __hash__ = None

    def __eq__(self, other):
        return vars(self) == vars(other)

    def __ne__(self, other):
        return not (self == other)

    def __contains__(self, key):
        return key in self.__dict__

경고 비우기:어떤 이유로 인해 이러한 클래스는 멀티프로세싱 패키지를 망가뜨리는 것처럼 보입니다.이 버그를 발견하기 전에 잠시 이 버그로 고생했습니다.SO: python multiprocessing에서 예외 발견

파이썬 생태계에서 "성격으로서의 딕트 키"의 현재 상태가 궁금했다.몇몇 논객들이 지적했듯이, 이것은 아마도 처음부터 스스로 굴리고 싶은 것이 아닐 이다. 몇 가지 함정과 발포가 있고, 그 중 몇 가지는 매우 미묘하기 때문이다.또, 이 기능을 사용하는 것은 추천하지 않습니다.Namespace기초반으로 가봤는데 별로 안 예쁘네요

다행히 이 기능을 제공하는 오픈 소스 패키지가 여러 개 있어 즉시 설치할 수 있습니다.아쉽게도 몇 가지 패키지가 있습니다.다음은 2019년 12월 시놉시스입니다.

컨텐더(마스터링에 대한 최신 커밋|#commits|#contribs|커버리지%):

더 이상 유지보수가 부족하지 않습니다.

  • treedic (2014-03-28 | 95 | 2 | ?%)
  • 번치(2012-03-12 | 20 | 2 | ?%)
  • 네오번치

나는 현재 뭉크나 중독자를 추천한다.이들은 가장 많은 커밋, 기여자 및 릴리스를 가지고 있어 각각에 대해 건전한 오픈소스 코드베이스를 제안합니다.가장 깔끔한 readme.md, 100% 커버리지 및 보기 좋은 테스트 세트를 갖추고 있습니다.

저는 이 경주에서 개를 키우지 않고 있습니다.그것은 저만의 dict/attr 코드를 굴려서 이 모든 옵션을 몰랐기 때문에 많은 시간을 낭비한 것 뿐입니다.조각난 패키지보다 단단한 패키지 하나를 보고 싶기 때문에 향후 중독/진창의 원인이 될 수 있습니다.마음에 드시면 기고하세요!특히 뭉크는 코덱코프 배지를, 중독자는 파이썬 버전 배지를 사용할 수 있는 것 같습니다.

중독자 프로:

  • 재귀 초기화(foo.a.b.c = 'bar'), dict와 같은 인수가 중독됩니다.딕트

중독자 단점:

  • typing.Dict 그렇다면from addict import Dict
  • 키 확인 없음.재귀적인 초기화가 가능하기 때문에 키의 철자를 틀렸을 경우 KeyError가 아닌 새로운 Atribute만 작성됩니다(AljoSt 감사합니다).

우적우적 찬성:

  • 고유 명명
  • JSON 및 YAML용 내장 ser/de 기능

단점:

  • init(재귀 init(재귀 init)는 할 수 )foo.a.b.c = 'bar' , , , 을 .foo.a , , , 「 」foo.a.b 등등.

내가 편집하는 곳

오래 전에 텍스트 에디터를 사용하여 파이썬을 작성했을 때, 저 자신이나 다른 개발자가 있는 프로젝트에서는 dict-attrs의 스타일이 좋았습니다.그냥 선언하는 것만으로 키를 삽입할 수 있는 것이 좋았습니다.foo.bar.spam = eggs지금은 팀을 이루어 모든 것에 IDE를 사용하고 있습니다.일반적으로 이런 종류의 데이터 구조나 동적 타이핑에서 벗어나 정적 분석, 기능 기술, 유형 힌트를 선호합니다.저는 이 기술을 실험하기 시작했습니다. 프스트룩트

class  BasePstruct(dict):
    def __getattr__(self, name):
        if name in self.__slots__:
            return self[name]
        return self.__getattribute__(name)

    def __setattr__(self, key, value):
        if key in self.__slots__:
            self[key] = value
            return
        if key in type(self).__dict__:
            self[key] = value
            return
        raise AttributeError(
            "type object '{}' has no attribute '{}'".format(type(self).__name__, key))


class FooPstruct(BasePstruct):
    __slots__ = ['foo', 'bar']

이렇게 하면 여전히 dict처럼 동작하는 객체를 얻을 수 있을 뿐만 아니라 속성 등의 키에 훨씬 더 엄격한 방식으로 액세스할 수 있습니다.여기서의 장점은 나(또는 코드의 불운한 소비자)가 어떤 필드가 존재할 수 있는지 정확히 알고 있으며 IDE는 필드를 자동으로 완료할 수 있다는 것입니다. .dict 것을 의미합니다.json의 시리얼화는 간단합니다.이 아이디어의 다음 진화는 이러한 인터페이스를 방출하는 커스텀프로토부프 제너레이터가 될 것입니다.좋은 점은 gRPC를 통해 크로스 언어 데이터 구조와 IPC를 거의 무료로 얻을 수 있다는 것입니다.

만약 attr-dicts를 선택하기로 결정한다면, 당신 자신과 동료들의 제정신을 위해 어떤 필드가 필요한지를 문서화하는 것이 중요합니다.

이 투고를 자유롭게 편집/갱신하여 최신 상태로 유지하십시오!

'키'를 원하는 할까요__eq__ ★★★★★★★★★★★★★★★★★」__getattr__

하지 않은 수 에 이렇게 쓰시면 래서,, 、 「 」0343853열쇠가 빠졌으니까

그리고 만약 당신이 끈을 사용하고 싶지 않다면요?

tuples는 dict 키를 사용할 수 있습니다.구축에서 태플에 어떻게 액세스하시겠습니까?

또한 namedtuple은 속성 접근을 통해 값을 제공할 수 있는 편리한 구조입니다.

내가 그들 모두를 지배하기 위해 쓴 작은 Python 클래스인 Prodict는 어때?

또한 자동 코드 완성, 재귀 객체 인스턴스화자동 유형 변환이 가능합니다.

원하는 대로 정확하게 수행할 수 있습니다.

p = Prodict()
p.foo = 1
p.bar = "baz"

예 1: 유형 힌트

class Country(Prodict):
    name: str
    population: int

turkey = Country()
turkey.name = 'Turkey'
turkey.population = 79814871

자동 코드 완료

예 2: 자동 유형 변환

germany = Country(name='Germany', population='82175700', flag_colors=['black', 'red', 'yellow'])

print(germany.population)  # 82175700
print(type(germany.population))  # <class 'int'>

print(germany.flag_colors)  # ['black', 'red', 'yellow']
print(type(germany.flag_colors))  # <class 'list'>

그것은 일반적으로 작동하지 않는다.유효한 모든 dict 키가 주소 지정 가능한 속성("키")을 만드는 것은 아닙니다.그러니 조심하셔야 합니다.

Python 개체는 기본적으로 모두 사전입니다.그래서 나는 많은 실적이나 다른 벌칙이 있는지 의심스럽다.

이것은 원래의 질문에는 대응하지 않지만, 저처럼 이 기능을 제공하는 lib를 찾을 때 도움이 될 것입니다.

중독성: https://github.com/mewwts/addict은 이전 답변에서 언급된 많은 우려를 해결해 줍니다.

문서의 예를 다음에 나타냅니다.

body = {
    'query': {
        'filtered': {
            'query': {
                'match': {'description': 'addictive'}
            },
            'filter': {
                'term': {'created_by': 'Mats'}
            }
        }
    }
}

중독자의 경우:

from addict import Dict
body = Dict()
body.query.filtered.query.match.description = 'addictive'
body.query.filtered.filter.term.created_by = 'Mats'

sci-kit learn은 단지 답변에 다양성을 더하기 위해 이것을 구현했습니다.Bunch:

class Bunch(dict):                                                              
    """ Scikit Learn's container object                                         

    Dictionary-like object that exposes its keys as attributes.                 
    >>> b = Bunch(a=1, b=2)                                                     
    >>> b['b']                                                                  
    2                                                                           
    >>> b.b                                                                     
    2                                                                           
    >>> b.c = 6                                                                 
    >>> b['c']                                                                  
    6                                                                           
    """                                                                         

    def __init__(self, **kwargs):                                               
        super(Bunch, self).__init__(kwargs)                                     

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

    def __dir__(self):                                                          
        return self.keys()                                                      

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

    def __setstate__(self, state):                                              
        pass                       

한 것은 오직 '만들기'를 얻는 이다.setattr ★★★★★★★★★★★★★★★★★」getattr- " " " - "getattrdict는 Attribute입니다.setstaet"번치"를 피클링/피클링하기 위한 수정 프로그램입니다.추가되지 않은 경우 https://github.com/scikit-learn/scikit-learn/issues/6196를 참조하십시오.

다음은 빌트인을 사용한 불변 레코드의 간단한 예입니다.

def record(name, d):
    return namedtuple(name, d.keys())(**d)

및 사용 예:

rec = record('Model', {
    'train_op': train_op,
    'loss': loss,
})

print rec.loss(..)

이 라이브러리에는 https://pypi.python.org/pypi/attrdict가 있는 것 같습니다.이 라이브러리에는 이 정확한 기능과 재귀적인 머지 및 json 로딩이 구현되어 있습니다.한 번 볼만한 가치가 있을 거야

내가방 、 업업업업업할 。에서는, 「」를 할 수 .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!'
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']

Kinvais의 답변을 기반으로 구축되었지만 http://databio.org/posts/python_AttributeDict.html에서 제안된 AttributeDict의 아이디어를 통합한 또 다른 구현을 게시합니다.

이 버전의 장점은 중첩된 사전에서도 작동한다는 것입니다.

class AttrDict(dict):
    """
    A class to convert a nested Dictionary into an object with key-values
    that are accessible using attribute notation (AttrDict.attribute) instead of
    key notation (Dict["key"]). This class recursively sets Dicts to objects,
    allowing you to recurse down nested dicts (like: AttrDict.attr.attr)
    """

    # Inspired by:
    # http://stackoverflow.com/a/14620633/1551810
    # http://databio.org/posts/python_AttributeDict.html

    def __init__(self, iterable, **kwargs):
        super(AttrDict, self).__init__(iterable, **kwargs)
        for key, value in iterable.items():
            if isinstance(value, dict):
                self.__dict__[key] = AttrDict(value)
            else:
                self.__dict__[key] = value

이게 내가 쓰는 거야

args = {
        'batch_size': 32,
        'workers': 4,
        'train_dir': 'train',
        'val_dir': 'val',
        'lr': 1e-3,
        'momentum': 0.9,
        'weight_decay': 1e-4
    }
args = namedtuple('Args', ' '.join(list(args.keys())))(**args)

print (args.lr)

가장 쉬운 방법은 네임스페이스라고 하는 클래스를 정의하는 것입니다.이 명령어는 dict.update() 오브젝트를 사용합니다.그러면 dict가 객체로 취급됩니다.

class Namespace(object):
    '''
    helps referencing object in a dictionary as dict.key instead of dict['key']
    '''
    def __init__(self, adict):
        self.__dict__.update(adict)



Person = Namespace({'name': 'ahmed',
                     'age': 30}) #--> added for edge_cls


print(Person.name)

아래의 이유로 기존 옵션에 만족하지 못하고 MetaDict를 개발하였습니다.그것은 정확히 같은 동작을 합니다.dict그러나 다른 솔루션의 단점이나 잠재적인 네임스페이스 충돌 없이 점 표기 및 IDE 자동 완성이 가능합니다.모든 기능 및 사용 예는 GitHub에서 확인할 수 있습니다(위 링크 참조).

완전 공개:는 메타딕트의 작가입니다.

다른 솔루션을 시험할 때 발생한 단점/제한 사항:

  • 중독자
    • IDE에 키 자동 완성 없음
    • 중첩된 키 할당을 끌 수 없습니다.
    • 할당된 " " "dict key 를 되지 않습니다.
    • 【우우】Dict
  • Prodict(프로덕트)
    • 스키마를 ).dataclass)
    • dict에 포함되어 있는 )list inbuilt ( in orererererer )
  • 특성
    • IDE에 키 자동 완성 없음
    • 「」를 합니다.list to 한 objects 。tuple
  • 뭉게뭉게
    • (예: like like like like like like like like like like like like like)items(),update()은 , 등으로 수 .obj.items = [1, 2, 3]
    • dict에 포함되어 있는 )list inbuilt ( in orererererer )
  • 이지딕트
    • 한 키는 이 는 유효합니다.dict는 모든 를 키로 .
    • (예: like like like like like like like like like like like like like)items(),update()은 , 등으로 수 .obj.items = [1, 2, 3]
    • 된 방법은 하지 않습니다.obj.pop('unknown_key', None)을 벌다AttributeError

setattr() 및 getattr()로 직접 쓸 필요가 없습니다.

클래스 객체의 이점은 클래스 정의와 상속에서 나타날 수 있습니다.

이 스레드로부터의 입력을 바탕으로 작성했습니다.하지만 난 악취를 사용해야만 해, 그래서 get and setting attrat를 무시해야 했어.대부분의 특수 용도에는 사용할 수 있을 것 같습니다.

사용 방법은 다음과 같습니다.

# Create an ordered dict normally...
>>> od = OrderedAttrDict()
>>> od["a"] = 1
>>> od["b"] = 2
>>> od
OrderedAttrDict([('a', 1), ('b', 2)])

# Get and set data using attribute access...
>>> od.a
1
>>> od.b = 20
>>> od
OrderedAttrDict([('a', 1), ('b', 20)])

# Setting a NEW attribute only creates it on the instance, not the dict...
>>> od.c = 8
>>> od
OrderedAttrDict([('a', 1), ('b', 20)])
>>> od.c
8

클래스:

class OrderedAttrDict(odict.OrderedDict):
    """
    Constructs an odict.OrderedDict with attribute access to data.

    Setting a NEW attribute only creates it on the instance, not the dict.
    Setting an attribute that is a key in the data will set the dict data but 
    will not create a new instance attribute
    """
    def __getattr__(self, attr):
        """
        Try to get the data. If attr is not a key, fall-back and get the attr
        """
        if self.has_key(attr):
            return super(OrderedAttrDict, self).__getitem__(attr)
        else:
            return super(OrderedAttrDict, self).__getattr__(attr)


    def __setattr__(self, attr, value):
        """
        Try to set the data. If attr is not a key, fall-back and set the attr
        """
        if self.has_key(attr):
            super(OrderedAttrDict, self).__setitem__(attr, value)
        else:
            super(OrderedAttrDict, self).__setattr__(attr, value)

이것은 스레드에서 이미 언급되어 있는 꽤 멋진 패턴입니다만, IDE 등에서 자동 완성 기능을 하는 오브젝트로 변환하는 것만으로, 다음과 같습니다.

class ObjectFromDict(object):
    def __init__(self, d):
        self.__dict__ = d

이 방법으로 dict 키에 액세스 할 때의 주의사항과 함정은 무엇입니까?

@Henry에서 알 수 있듯이 dot-access가 dicts에서 사용되지 않는 이유 중 하나는 dict 키 이름을 python-valid 변수로 제한하여 가능한 모든 이름을 제한하기 때문입니다.

ditit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, , , dit, , dit, dit, dit, dit, dit, dit, dit, dit, dit, dit, , dit, dit, ditd:

유효성

다음 속성은 Python에서 유효하지 않습니다.

d.1_foo                           # enumerated names
d./bar                            # path names
d.21.7, d.12:30                   # decimals, time
d.""                              # empty strings
d.john doe, d.denny's             # spaces, misc punctuation 
d.3 * x                           # expressions  

스타일.

PEP8 규약은 Atribute naming에 소프트 제약을 가합니다.

A. Reserved 키워드(또는 내장 함수) 이름:

d.in
d.False, d.True
d.max, d.min
d.sum
d.id

함수 인수의 이름이 예약된 키워드와 충돌할 경우 일반적으로 후행 언더스코어를 하나 추가하는 것이 좋습니다.

B. 메서드 및 변수 이름에 대한 대소문자 규칙:

변수 이름은 함수 이름과 동일한 규칙을 따릅니다.

d.Firstname
d.Country

필요에 따라 소문자 및 밑줄로 구분된 이름을 사용하여 읽기 쉽게 합니다.


때때로 이러한 우려는 판다와 같은 라이브러리에서 제기되기도 합니다. 판다에서는 DataFrame 열을 이름으로 닷으로 액세스할 수 있습니다.명명 제한을 해결하기 위한 기본 메커니즘도 대괄호 안의 문자열인 배열 주석입니다.

이러한 제약사항이 사용 사례에 적용되지 않는 경우, 도트 액세스 데이터 구조에는 몇 가지 옵션이 있습니다.

이 대답은 루치아노 라말호가 쓴 책 Fluent Python에서 따왔다.저 남자한테 공을 돌려줘요.

class AttrDict:
    """A read-only façade for navigating a JSON-like object
    using attribute notation
    """

    def __init__(self, mapping):
        self._data = dict(mapping)

    def __getattr__(self, name):
        if hasattr(self._data, name):
            return getattr(self._data, name)
        else:
            return AttrDict.build(self._data[name])

    @classmethod
    def build(cls, obj):
        if isinstance(obj, Mapping):
            return cls(obj)
        elif isinstance(obj, MutableSequence):
            return [cls.build(item) for item in obj]
        else:
            return obj

init에서 우리는 dict를 받아 사전을 만들고 있다.getattr을 사용할 때 dict에 이미 속성이 있는 경우 dict에서 속성을 얻으려고 합니다.그렇지 않으면 인수를 빌드라고 하는 클래스 메서드에 전달합니다.이제 build는 흥미로운 일을 합니다. 만약 객체가 dict 또는 그와 같은 매핑이라면, 그 객체는 그 자체로 attr dict가 됩니다.리스트와 같은 시퀀스의 경우는, 현재 사용하고 있는 빌드 함수에 건네집니다.스트린이나 int와 같은 씬의 경우는 오브젝트 자체를 반환해 주세요.

사용방법:

from types import SimpleNamespace

obj = SimpleNamespace(color="blue", year=2050)

print(obj.color) #> "blue"
print(obj.year) #> 2050

편집/업데이트: 사전에서 시작하는 OP 질문에 대한 보다 가까운 답변:

from types import SimpleNamespace

params = {"color":"blue", "year":2020}

obj = SimpleNamespace(**params)

print(obj.color) #> "blue"
print(obj.year) #> 2050

class AttrDict(dict):

     def __init__(self):
           self.__dict__ = self

if __name__ == '____main__':

     d = AttrDict()
     d['ray'] = 'hope'
     d.sun = 'shine'  >>> Now we can use this . notation
     print d['ray']
     print d.sun

솔루션은 다음과 같습니다.

DICT_RESERVED_KEYS = vars(dict).keys()


class SmartDict(dict):
    """
    A Dict which is accessible via attribute dot notation
    """
    def __init__(self, *args, **kwargs):
        """
        :param args: multiple dicts ({}, {}, ..)
        :param kwargs: arbitrary keys='value'

        If ``keyerror=False`` is passed then not found attributes will
        always return None.
        """
        super(SmartDict, self).__init__()
        self['__keyerror'] = kwargs.pop('keyerror', True)
        [self.update(arg) for arg in args if isinstance(arg, dict)]
        self.update(kwargs)

    def __getattr__(self, attr):
        if attr not in DICT_RESERVED_KEYS:
            if self['__keyerror']:
                return self[attr]
            else:
                return self.get(attr)
        return getattr(self, attr)

    def __setattr__(self, key, value):
        if key in DICT_RESERVED_KEYS:
            raise AttributeError("You cannot set a reserved name as attribute")
        self.__setitem__(key, value)

    def __copy__(self):
        return self.__class__(self)

    def copy(self):
        return self.__copy__()

dict_to_ohttp://https://pypi.org/project/dict-to-obj/ 를 사용할 수 있습니다. 요청하신 대로 작동합니다.

From dict_to_obj import DictToObj
a = {
'foo': True
}
b = DictToObj(a)
b.foo
True

이것은 '좋은' 답변은 아니지만, 저는 이것이 좋다고 생각했습니다(현재 형식의 중첩된 딕트는 처리하지 않습니다).간단히 함수로 받아쓰기를 마무리합니다.

def make_funcdict(d=None, **kwargs)
    def funcdict(d=None, **kwargs):
        if d is not None:
            funcdict.__dict__.update(d)
        funcdict.__dict__.update(kwargs)
        return funcdict.__dict__
    funcdict(d, **kwargs)
    return funcdict

이제 구문이 약간 다릅니다.하려면 dict를 수행합니다.f.key. 항목 메서드으로 액세스하려면 .dict ( dict dict methods )를 사용합니다.f()['key']할 수 있습니다.

d = {'name':'Henry', 'age':31}
d = make_funcdict(d)
>>> for key in d():
...     print key
... 
age
name
>>> print d.name
... Henry
>>> print d.age
... 31
>>> d({'Height':'5-11'}, Job='Carpenter')
... {'age': 31, 'name': 'Henry', 'Job': 'Carpenter', 'Height': '5-11'}

그것이 저기 있네.이 방법의 장점과 단점을 제안하는 사람이 있으면 좋겠습니다.

편집: NeoBunch는 디프로필되어 있습니다.먼치(상기)는 드롭인 교환용으로 사용할 수 있습니다.하지만 그 해결책은 여기 두겠습니다. 누군가에게 유용할 수 있습니다.

와 같이, Doug를 달성하기 할 수 obj.key★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

네오번치 뭉게뭉게

neobunchify 기능을 통해 dict를 NeoBunch 객체로 변환하는 뛰어난 기능을 갖추고 있습니다.저는 Mako 템플릿을 많이 사용하고 NeoBunch 오브젝트로 데이터를 전달하면 읽기 쉬우므로 Python 프로그램에서 일반 dit를 사용하게 되지만 Mako 템플릿의 닷 표기법을 원할 경우 다음과 같이 사용할 수 있습니다.

from mako.template import Template
from neobunch import neobunchify

mako_template = Template(filename='mako.tmpl', strict_undefined=True)
data = {'tmpl_data': [{'key1': 'value1', 'key2': 'value2'}]}
with open('out.txt', 'w') as out_file:
    out_file.write(mako_template.render(**neobunchify(data)))

Mako 템플릿은 다음과 같습니다.

% for d in tmpl_data:
Column1     Column2
${d.key1}   ${d.key2}
% endfor

언급URL : https://stackoverflow.com/questions/4984647/accessing-dict-keys-like-an-attribute

반응형