객체 필드의 파이썬 사전


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 항목을 잡고 '__'으로 시작하는 것을 막는 것입니다.

일단 생성 한 후에 dictupdatedict 함수를 사용 하여 인스턴스를 전달할 수 있습니다 __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.