Frage

Sie wissen, ob es eine eingebaute Funktion ist ein Wörterbuch von einem beliebigen Objekt zu bauen? Ich möchte so etwas wie dies tun:

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

Hinweis: Es sollte nicht Methoden umfassen. Nur Felder aus.

War es hilfreich?

Lösung

Beachten Sie, dass Best Practice in Python 2.7 zu verwenden ist new-style Klassen (nicht mit Python 3 benötigt), dh

class Foo(object):
   ...

Außerdem gibt es einen Unterschied zwischen einem ‚Objekt‘ und einer ‚Klasse‘. Um einen Wörterbuch aus einem beliebigen Objekt zu bauen , dann ist es ausreichend __dict__ zu verwenden. Normalerweise werden Sie Ihre Methoden auf Klassenebene und Ihre Attribute auf Instanzebene deklarieren, so sollte __dict__ in Ordnung sein. Zum Beispiel:

>>> 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}

Ein besserer Ansatz (vorgeschlagen von robert in den Kommentaren) ist die builtin vars Funktion:

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

Alternativ, je nachdem, was Sie tun wollen, könnte es schön, von dict zu erben. Dann ist Ihre Klasse ist bereits ein Wörterbuch, und wenn Sie möchten, dass Sie getattr außer Kraft setzen können und / oder setattr zu rufen durch und die dict gesetzt. Zum Beispiel:

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

    # etc...

Andere Tipps

Statt x.__dict__, es ist eigentlich mehr pythonic vars(x) zu verwenden.

Die dir builtin geben Ihnen alle Objektattribute, darunter spezielle Methoden wie __str__, __dict__ und eine ganze Reihe von anderen, die Sie wahrscheinlich nicht wollen. Aber man kann so etwas tun:

>>> 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' }

So kann diese erweitern, um nur Datenattribute zurückgeben und nicht die Methoden, indem Sie Ihre props Funktion wie folgt definieren:

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

Ich habe mit einer Kombination aus beiden Antworten angesiedelt:

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

ein Wörterbuch von einem beliebigen Objekt bauen , es ist ausreichend __dict__ zu verwenden.

Dieses vermißt Attribute, die das Objekt von seiner Klasse übernimmt. Zum Beispiel:

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

hasattr (a, 'x') ist wahr, aber 'x' erscheint nicht in einem .__ dict __

Ich dachte, ich einige Zeit dauern würde Ihnen zu zeigen, wie Sie ein Objekt übersetzen kann über dict(obj) dict.

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'}"

Der Schlüssel Abschnitt dieses Codes ist die __iter__ Funktion.

Wie die Kommentare erklären, das erste, was wir tun, ist die Klasse Gegenstände greifen und etwas zu verhindern, die mit beginnt ‚__‘.

Wenn Sie diese dict erstellt haben, dann können Sie die update dict-Funktion verwenden und in der Instanz __dict__ passieren.

Diese geben Ihnen eine komplette Klasse + Instanz Wörterbuch der Mitglieder. Jetzt alles, was übrig bleibt, ist über sie zu durchlaufen und die Erträge abwerfen.

Auch wenn Sie sich mit diesen viel planen, können Sie eine @iterable Klasse Dekorateur erstellen.

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))

Späte Antwort, aber auf Vollständigkeit und der Nutzen der Googler vorgesehen:

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

Dies wird nicht Methoden in der Klasse definiert zeigen, aber es wird noch zeigen Felder einschließlich der zugeordneten Lambda-Ausdrücke oder solche, die mit einem doppelten Unterstrich beginnen.

Ich denke, der einfachste Weg ist es, ein getitem Attribut für die Klasse zu erstellen. Wenn Sie auf das Objekt schreiben, dann können Sie eine benutzerdefinierte setattr erstellen. Hier ist ein Beispiel für 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 die Objekte erzeugt Attribute in ein Wörterbuch und das Wörterbuch-Objekt kann verwendet werden, um die Artikel, die Sie benötigen.

Wenn Sie einen Teil Ihrer Attribute aufzulisten, außer Kraft setzen __dict__:

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

# Call __dict__
d = instance.__dict__()

Dies ist sehr hilfreich, wenn Ihr instance einige große Blockdaten erhalten, und Sie wollen d schieben wie Nachrichtenwarteschlange Redis.

Ein Nachteil __dict__ der Verwendung ist, dass es flach ist; es wird keine Subklassen Wörterbücher konvertieren.

Wenn Sie Python3.5 oder höher verwenden, können Sie jsons :

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

PYTHON 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

Jetzt können Sie über Code in Ihrer eigenen Klasse verwenden:

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() 
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top