객체 필드의 파이썬 사전


344

임의의 객체에서 사전을 작성하는 내장 함수가 있는지 알고 있습니까? 나는 이런 식으로하고 싶다 :

>>> class Foo:
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> props(f)
{ 'bar' : 'hello', 'baz' : 'world' }

참고 : 방법을 포함해서는 안됩니다. 필드 만.

답변:


422

Python 2.7의 모범 사례는 새로운 스타일 클래스 (Python 3에서는 필요하지 않음)를 사용하는 것입니다.

class Foo(object):
   ...

또한 '객체'와 '클래스'에는 차이가 있습니다. 임의의 객체 에서 사전을 만들려면 사용하기에 충분합니다 __dict__. 일반적으로 클래스 수준에서 메소드를 선언하고 인스턴스 레벨에서 속성을 선언하므로 __dict__좋을 것입니다. 예를 들면 다음과 같습니다.

>>> class A(object):
...   def __init__(self):
...     self.b = 1
...     self.c = 2
...   def do_nothing(self):
...     pass
...
>>> a = A()
>>> a.__dict__
{'c': 2, 'b': 1}

더 나은 접근법 ( 로버트 가 주석에서 제안 )은 내장 vars함수입니다.

>>> vars(a)
{'c': 2, 'b': 1}

또는 원하는 작업에 따라에서 상속하는 것이 좋습니다 dict. 그런 다음 클래스는 이미 사전이며 원하는 경우 dict을 재정의 getattr및 / 또는 setattr호출하고 설정할 수 있습니다 . 예를 들면 다음과 같습니다.

class Foo(dict):
    def __init__(self):
        pass
    def __getattr__(self, attr):
        return self[attr]

    # etc...

3
A의 속성 중 하나에 사용자 지정 getter가 있으면 어떻게됩니까? (@property 데코레이터 기능)? 여전히 ____dict____에 표시됩니까? 그 가치는 무엇입니까?
— zakdances

11
__dict__객체가 슬롯을 사용하거나 C 모듈에 정의되어 있으면 작동하지 않습니다.
— 안티몬

1
클래스 객체에 대해이 방법과 동등한 것이 있습니까? IE f = Foo ()를 사용하고 f .__ dict__를 수행하는 대신 Foo .__ dict__를 직접 수행합니까?
— chiffa

49
죄송합니다. 늦게오고 있는데 이러면 안되나요 vars(a)? 나를 위해 __dict__직접 호출하는 것이 좋습니다 .
— robert

2
두 번째 예는 어떻게 더 나은 것 __getattr__ = dict.__getitem__당신도 원하는 것이 정확히 동작을 복제 __setattr__ = dict.__setitem__하고 __delattr__ = dict.__delitem__완벽한 다움을 위해.
— Tadhg McDonald-Jensen

141

대신에 x.__dict__, 실제로 사용하기가 더 pythonic vars(x)입니다.


3
동의했다. MyClass(**my_dict)클래스 속성을 미러링하는 매개 변수로 생성자를 정의했다고 가정하면 을 입력하여 다른 방법으로 (dict-> class) 변환 할 수도 있습니다 . 개인 속성에 액세스하거나 dict을 무시할 필요가 없습니다.
— tvt173

2
왜 더 파이썬 적인지 설명 할 수 있습니까?
— 휴 W

1
첫째, 파이썬은 일반적으로 호출하는 항목을 직접 호출하지 않으며, 간접적으로 액세스하는 메소드 또는 함수 (또는 연산자)는 거의 항상 있습니다. 일반적으로 Dunder 속성과 메소드는 구현 세부 사항이며 "래퍼"기능을 사용하면 둘을 분리 할 수 ​​있습니다. 둘째,이 방법으로 vars객체 자체를 변경하지 않고도 기능을 무시하고 추가 기능을 도입 할 수 있습니다 .
— Berislav Lopac

1
클래스가 __slots__그래도 여전히 실패합니다 .
— cz

맞습니다. 저는 늘 확장하는 것이 좋은 방향이라고 생각했습니다 vars. 즉, __dict__"슬롯 된"클래스에 상응하는 것을 반환하는 것 입니다. 지금 __dict__은 반환 하는 속성을 추가하여 에뮬레이션 할 수 있습니다 {x: getattr(self, x) for x in self.__slots__}(성능이나 동작에 어떤 영향을 미치는지 확실하지 않음).
— Berislav Lopac

59

dir내장 당신에게 같은 특별한 방법을 포함하는 모든 객체의 속성을 줄 것이다 __str__, __dict__당신은 아마 원하지 않는 다른 사람의 전체 무리를. 그러나 다음과 같은 것을 할 수 있습니다.

>>> class Foo(object):
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> [name for name in dir(f) if not name.startswith('__')]
[ 'bar', 'baz' ]
>>> dict((name, getattr(f, name)) for name in dir(f) if not name.startswith('__')) 
{ 'bar': 'hello', 'baz': 'world' }

따라서 다음 props과 같이 함수 를 정의하여 메소드가 아닌 데이터 속성 만 리턴하도록이를 확장 할 수 있습니다 .

import inspect

def props(obj):
    pr = {}
    for name in dir(obj):
        value = getattr(obj, name)
        if not name.startswith('__') and not inspect.ismethod(value):
            pr[name] = value
    return pr

1
이 코드에는 메소드가 포함되어 있습니다. 방법을 배제하는 방법이 있습니까? 객체의 필드 만 필요합니다. 감사합니다
— Julio César

ismethod기능을 포착하지 않습니다. 예 : inspect.ismethod(str.upper). inspect.isfunction그래도 더 도움이되지 않습니다. 어떻게 바로 접근 해야할지 모르겠습니다.
— Ehtesh Choudhury

나는 조잡하게 되풀이하고 모든 오류를 깊이 무시하기 위해 약간의 조정을했습니다. 감사합니다! gist.github.com/thorsummoner/bf0142fd24974a0ced778768a33a3069
— ThorSummoner

26

나는 두 답변의 조합으로 정착했습니다.

dict((key, value) for key, value in f.__dict__.iteritems() 
    if not callable(value) and not key.startswith('__'))

그것은 또한 작동하지만 클래스가 아닌 인스턴스에 설정된 속성 만 제공한다는 것을 알고 있어야합니다 (예 : 클래스 Foo와 같은) ...
— dF.

따라서 jcarrascal에서는 위의 코드를 props ()와 같은 함수로 래핑하는 것이 좋습니다. props (f) 또는 props (Foo)를 호출 할 수 있습니다. '인라인'코드를 작성하는 것보다 함수를 작성하는 것이 거의 항상 낫습니다.
— quamrana

니스, btw는 이것이 python2.7 용이며 python3 relpace iteritems ()는 items ()입니다.
— Morten

그리고 staticmethod어때요? 아닙니다 callable.
— Alex

17

객체를 dict로 변환하는 방법을 보여주기 위해 시간이 걸릴 것이라고 생각했습니다 dict(obj).

class A(object):
    d = '4'
    e = '5'
    f = '6'

    def __init__(self):
        self.a = '1'
        self.b = '2'
        self.c = '3'

    def __iter__(self):
        # first start by grabbing the Class items
        iters = dict((x,y) for x,y in A.__dict__.items() if x[:2] != '__')

        # then update the class items with the instance items
        iters.update(self.__dict__)

        # now 'yield' through the items
        for x,y in iters.items():
            yield x,y

a = A()
print(dict(a)) 
# prints "{'a': '1', 'c': '3', 'b': '2', 'e': '5', 'd': '4', 'f': '6'}"

이 코드의 핵심 부분은 __iter__ 함수입니다.

의견에서 알 수 있듯이 가장 먼저 할 일은 Class 항목을 잡고 '__'으로 시작하는 것을 막는 것입니다.

일단 생성 한 후에 dict는 updatedict 함수를 사용 하여 인스턴스를 전달할 수 있습니다 __dict__.

이들은 당신에게 회원의 완전한 클래스 + 인스턴스 사전을 제공합니다. 이제 남은 것은 그것들을 반복하고 수익을 얻는 것입니다.

또한 이것을 많이 사용할 계획이라면 @iterable클래스 데코레이터를 만들 수 있습니다 .

def iterable(cls):
    def iterfn(self):
        iters = dict((x,y) for x,y in cls.__dict__.items() if x[:2] != '__')
        iters.update(self.__dict__)

        for x,y in iters.items():
            yield x,y

    cls.__iter__ = iterfn
    return cls

@iterable
class B(object):
    d = 'd'
    e = 'e'
    f = 'f'

    def __init__(self):
        self.a = 'a'
        self.b = 'b'
        self.c = 'c'

b = B()
print(dict(b))

이것은 또한 모든 메소드를 가져 오지만 클래스 + 인스턴스 필드 만 필요합니다. 어쩌면 dict((x, y) for x, y in KpiRow.__dict__.items() if x[:2] != '__' and not callable(y))그것을 해결할 것입니까? 그러나 여전히 static방법 이있을 수 있습니다 :(
— Alex

15

임의의 객체 에서 사전을 만들려면 사용하기에 충분합니다 __dict__.

객체가 클래스에서 상속하는 속성이 누락되었습니다. 예를 들어

class c(object):
    x = 3
a = c()

hasattr (a, 'x')는 true이지만 'x'는 a .__ dict__에 나타나지 않습니다.


이 경우 해결책은 무엇입니까? vars()작동하지 않기 때문에
— should_be_working

dir이 경우 @should_be_working 이 해결책입니다. 그것에 대한 다른 답변을 참조하십시오.
— Albert Albert

8

답변은 늦었지만 Google 직원의 완전성과 이점을 제공했습니다.

def props(x):
    return dict((key, getattr(x, key)) for key in dir(x) if key not in dir(x.__class__))

클래스에 정의 된 메소드는 표시되지 않지만 람다에 할당 된 필드 나 이중 밑줄로 시작하는 필드를 포함하는 필드가 계속 표시됩니다.


6

가장 쉬운 방법은 클래스 의 getitem 속성 을 만드는 것 입니다. 객체에 쓰려면 사용자 정의 setattr을 만들 수 있습니다 . 다음은 getitem 의 예입니다 .

class A(object):
    def __init__(self):
        self.b = 1
        self.c = 2
    def __getitem__(self, item):
        return self.__dict__[item]

# Usage: 
a = A()
a.__getitem__('b')  # Outputs 1
a.__dict__  # Outputs {'c': 2, 'b': 1}
vars(a)  # Outputs {'c': 2, 'b': 1}

dict 는 객체 속성을 사전에 생성하고 사전 객체를 사용하여 필요한 항목을 가져올 수 있습니다.


이 대답 후에도 개체에서 사전을 얻는 방법은 여전히 ​​명확하지 않습니다. 속성이 아니라 전체 사전;)
— maxkoryukov

6

사용의 단점 __dict__ 은 얕다는 것입니다. 하위 클래스를 사전으로 변환하지 않습니다.

Python3.5 이상을 사용하는 경우 다음을 사용할 수 있습니다 jsons.

>>> import jsons
>>> jsons.dump(f)
{'bar': 'hello', 'baz': 'world'}

3

속성의 일부를 나열하려면 다음을 대체하십시오 __dict__.

def __dict__(self):
    d = {
    'attr_1' : self.attr_1,
    ...
    }
    return d

# Call __dict__
d = instance.__dict__()

이것은 instance큰 블록 데이터를 얻고 d메시지 큐와 같이 Redis 에 푸시하려는 경우 많은 도움이됩니다 .


__dict__는 메소드가 아닌 속성이므로이 예제는 인터페이스를 변경하므로 (즉, 호출 가능 인터페이스로 호출해야 함) 재정의하지 않습니다.
— Berislav Lopac 2019 년

0

피톤 3 :

class DateTimeDecoder(json.JSONDecoder):

   def __init__(self, *args, **kargs):
        JSONDecoder.__init__(self, object_hook=self.dict_to_object,
                         *args, **kargs)

   def dict_to_object(self, d):
       if '__type__' not in d:
          return d

       type = d.pop('__type__')
       try:
          dateobj = datetime(**d)
          return dateobj
       except:
          d['__type__'] = type
          return d

def json_default_format(value):
    try:
        if isinstance(value, datetime):
            return {
                '__type__': 'datetime',
                'year': value.year,
                'month': value.month,
                'day': value.day,
                'hour': value.hour,
                'minute': value.minute,
                'second': value.second,
                'microsecond': value.microsecond,
            }
        if isinstance(value, decimal.Decimal):
            return float(value)
        if isinstance(value, Enum):
            return value.name
        else:
            return vars(value)
    except Exception as e:
        raise ValueError

이제 자신의 클래스 내에서 위 코드를 사용할 수 있습니다.

class Foo():
  def toJSON(self):
        return json.loads(
            json.dumps(self, sort_keys=True, indent=4, separators=(',', ': '), default=json_default_format), cls=DateTimeDecoder)


Foo().toJSON() 

0

vars() 훌륭하지만 중첩 된 객체의 객체에는 작동하지 않습니다.

객체의 중첩 객체를 dict로 변환합니다.

def to_dict(self):
    return json.loads(json.dumps(self, default=lambda o: o.__dict__))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.