1515 Stimmen

Gibt es eine eingebaute Funktion, die alle aktuellen Eigenschaften und Werte eines Objekts ausgibt?

Was ich hier also suche, ist so etwas wie PHPs drucken_r Funktion.

So kann ich meine Skripte debuggen, indem ich den Zustand des betreffenden Objekts sehe.

1393voto

Jeremy Cantrell Punkte 24497

Sie wollen vars() gemischt mit pprint() :

from pprint import pprint
pprint(vars(your_object))

811voto

Sie vermischen hier wirklich zwei verschiedene Dinge miteinander.

Utilisez dir() , vars() oder die inspect Modul, um das zu bekommen, was Sie interessiert (ich verwende __builtins__ als Beispiel; Sie können stattdessen jedes beliebige Objekt verwenden).

>>> l = dir(__builtins__)
>>> d = __builtins__.__dict__

Drucken Sie das Wörterbuch aus, wie es Ihnen gefällt:

>>> print l
['ArithmeticError', 'AssertionError', 'AttributeError',...

ou

>>> from pprint import pprint
>>> pprint(l)
['ArithmeticError',
 'AssertionError',
 'AttributeError',
 'BaseException',
 'DeprecationWarning',
...

>>> pprint(d, indent=2)
{ 'ArithmeticError': <type 'exceptions.ArithmeticError'>,
  'AssertionError': <type 'exceptions.AssertionError'>,
  'AttributeError': <type 'exceptions.AttributeError'>,
...
  '_': [ 'ArithmeticError',
         'AssertionError',
         'AttributeError',
         'BaseException',
         'DeprecationWarning',
...

Pretty-Printing ist auch im interaktiven Debugger als Befehl verfügbar:

(Pdb) pp vars()
{'__builtins__': {'ArithmeticError': <type 'exceptions.ArithmeticError'>,
                  'AssertionError': <type 'exceptions.AssertionError'>,
                  'AttributeError': <type 'exceptions.AttributeError'>,
                  'BaseException': <type 'exceptions.BaseException'>,
                  'BufferError': <type 'exceptions.BufferError'>,
                  ...
                  'zip': <built-in function zip>},
 '__file__': 'pass.py',
 '__name__': '__main__'}

313voto

Dan Lenski Punkte 72055
def dump(obj):
  for attr in dir(obj):
    print("obj.%s = %r" % (attr, getattr(obj, attr)))

Es gibt viele Funktionen von Drittanbietern, die Dinge wie die Behandlung von Ausnahmen, die Ausgabe von nationalen Zeichen/Sonderzeichen, die Suche nach verschachtelten Objekten usw. je nach den Wünschen ihrer Autoren hinzufügen. Aber im Grunde laufen sie alle auf das Folgende hinaus.

116voto

eduffy Punkte 37562

dir wurde bereits erwähnt, aber damit erhalten Sie nur die Namen der Attribute. Wenn Sie auch deren Werte benötigen, versuchen Sie __dict__ .

class O:
   def __init__ (self):
      self.value = 3

o = O()

Hier ist die Ausgabe:

>>> o.__dict__

{'value': 3}

92voto

Gibt es eine eingebaute Funktion, die alle aktuellen Eigenschaften und Werte eines Objekts ausgibt?

Nein. Die am meisten hochgestimmte Antwort schließt einige Arten von Attributen aus, und die akzeptierte Antwort zeigt, wie man todo Attribute, einschließlich Methoden und Teile der nicht-öffentlichen API. Aber es gibt keine gute vollständige eingebautes Funktion dafür.

Die kurze Konsequenz ist also, dass Sie Ihre eigene schreiben können, aber sie wird Eigenschaften und andere berechnete Daten-Deskriptoren berechnen, die Teil der öffentlichen API sind, und das wollen Sie vielleicht nicht:

from pprint import pprint
from inspect import getmembers
from types import FunctionType

def attributes(obj):
    disallowed_names = {
      name for name, value in getmembers(type(obj)) 
        if isinstance(value, FunctionType)}
    return {
      name: getattr(obj, name) for name in dir(obj) 
        if name[0] != '_' and name not in disallowed_names and hasattr(obj, name)}

def print_attributes(obj):
    pprint(attributes(obj))

Probleme mit anderen Antworten

Beobachten Sie die Anwendung der aktuell am häufigsten gewählten Antwort auf eine Klasse mit vielen verschiedenen Arten von Datenmitgliedern:

from pprint import pprint

class Obj:
    __slots__ = 'foo', 'bar', '__dict__'
    def __init__(self, baz):
        self.foo = ''
        self.bar = 0
        self.baz = baz
    @property
    def quux(self):
        return self.foo * self.bar

obj = Obj('baz')
pprint(vars(obj))

druckt nur:

{'baz': 'baz'}

Denn vars nur __dict__ eines Objekts, und es ist keine Kopie. Wenn Sie also das von vars zurückgegebene dict ändern, ändern Sie auch das __dict__ des Objekts selbst.

vars(obj)['quux'] = 'WHAT?!'
vars(obj)

zurück:

{'baz': 'baz', 'quux': 'WHAT?!'}

-- was schlecht ist, weil quux eine Eigenschaft ist, die wir nicht setzen sollten und die nicht im Namensraum sein sollte...

Die Anwendung der Ratschläge in der derzeit akzeptierten Antwort (und anderen) ist nicht viel besser:

>>> dir(obj)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'bar', 'baz', 'foo', 'quux']

Wie wir sehen können, dir kehrt nur zurück todo (eigentlich nur die meisten) der mit einem Objekt verbundenen Namen.

inspect.getmembers die in den Kommentaren erwähnt wurde, ist ähnlich fehlerhaft - sie liefert alle Namen und Werte.

Von der Klasse

Im Unterricht lasse ich meine Studenten eine Funktion erstellen, die die semantisch öffentliche API eines Objekts bereitstellt:

def api(obj):
    return [name for name in dir(obj) if name[0] != '_']

Wir können dies erweitern, um eine kopieren. des semantischen Namensraums eines Objekts, aber wir müssen ausschließen __slots__ die nicht zugewiesen sind, und wenn wir die Forderung nach "aktuellen Eigenschaften" ernst nehmen, müssen wir berechnete Eigenschaften ausschließen (da sie teuer werden könnten und als nicht "aktuell" interpretiert werden könnten):

from types import FunctionType
from inspect import getmembers

def attrs(obj):
    disallowed_properties = {
        name for name, value in getmembers(type(obj)) 
        if isinstance(value, (property, FunctionType))
    }
    return {
        name: getattr(obj, name) for name in api(obj) 
        if name not in disallowed_properties and hasattr(obj, name)
    }

Und jetzt berechnen oder zeigen wir nicht die Eigenschaft, quux:

>>> attrs(obj)
{'bar': 0, 'baz': 'baz', 'foo': ''}

Vorbehalte

Aber vielleicht wissen wir ja, dass unsere Immobilien nicht teuer sind. Vielleicht wollen wir die Logik so ändern, dass auch sie berücksichtigt werden. Und vielleicht wollen wir ausschließen andere benutzerdefinierte stattdessen Daten-Deskriptoren.

Dann müssen wir diese Funktion weiter anpassen. Daher ist es logisch, dass wir keine eingebaute Funktion haben können, die auf magische Weise genau weiß, was wir wollen und es bereitstellt. Diese Funktion müssen wir selbst erstellen.

Schlussfolgerung

Es gibt keine eingebaute Funktion, die dies tut, und Sie sollten tun, was für Ihre Situation semantisch am besten geeignet ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X