Чи є вбудована функція для друку всіх поточних властивостей та значень об’єкта?


Відповіді:


590

Ви дійсно змішуєте дві різні речі.

Використовуйте dir(), vars()або inspectмодуль , щоб отримати те , що ви зацікавлені в тому, (я використовую в __builtins__якості прикладу, ви можете використовувати будь-який об'єкт , а).

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

Роздрукуйте цей словник, як вам не здається:

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

або

>>> 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',
...

Гарна друк також доступна в інтерактивному відладчику як команда:

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

28
Дивно, але, здається, не всі об'єкти мають __dict__члена ( re.MatchObjectнаприклад,), але вбудований dir()працює для всіх об'єктів.
варильні панелі

print re.compile(r'slots').search('No slots here either.').__slots__
варильні панелі

3
Нова для мене. Дякую. Крапка запустила аналізатор шляху мого мозку. Ніколи навіть не вважав латинським «модулем».
варильні панелі

4
чому б inspectу вашій відповіді більше не поговорити про модуль? Я думаю, що це найближче до print_r або var_dump.
Hai Phaikawl

1
Як тоді ви отримуєте доступ до значень, що стоять за переліченими атрибутами dir()? dir()повертає лише список імен, і не всі вони існують в атрибуті vars()або в ньому __dict__.
HelloGoodbye

981

Ви хочете vars()змішатись із pprint():

from pprint import pprint
pprint(vars(your_object))

24
vars()просто повертає __dict__свій аргумент, і це також є резервом, dir()якщо немає __dir__методу. тому використовуйте dir()в першу чергу, як я вже сказав.

28
@hop: dir()дає вам все вбудоване в речі, які вам, мабуть, не цікаві, як __str__і __new__. var()не робить.
Timmmm

14
Це не вдається встановити набори та інші об'єкти, які не мають __dict__атрибутів.
anatoly techtonik

209
def dump(obj):
  for attr in dir(obj):
    print("obj.%s = %r" % (attr, getattr(obj, attr)))

Існує багато функцій сторонніх виробників, які додають такі речі, як обробка виключень, національне / спеціальне друкування символів, повторне внесення вкладених об'єктів тощо відповідно до уподобань їхніх авторів. Але всі вони зводяться до цього.


5
непіфонічно, тому що тут не вигадано

14
Скажи що? Звичайно, ви можете використовувати getmembers()функцію в стандартному inspectмодулі, але я подумав, що це буде корисніше, оскільки вона ілюструє, як робити самоаналіз загалом.
Дан Ленськи

20
НЕ ВСІ. dir (obj) показує властивості, яких немає в __dict__(наприклад, __doc__та __module__). Крім того, __dict__взагалі не працює для об'єктів, декларованих з __slots__. Загалом, __dict__показує властивості рівня користувача, які фактично зберігаються у словнику всередині країни. dir () показує більше.
Дан Ленськи

8
Деякі класи / об’єкти не містять __dict__атрибутів / членів. Я знаю, що це божевільно, але правда. Вбудовані модулі , як intі strчи re.MatchObjectз є загальними прикладами. Спробуйте 'hello'.__dict__, тоді спробуйтеdir('hello')
варильні панелі

11
Мені байдуже, це «непітонічне» чи ні. Він виконує роботу, яка в налагодженні є єдиною важливою справою.
hidfromkgb

59

dir був згаданий, але це дасть вам лише імена атрибутів. Якщо ви хочете, щоб їх значення також спробуйте __dict__.

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

o = O()

Ось вихід:

>>> o.__dict__

{'value': 3}

9
Об'єктів начебто setнемає __dict__, тож для них це вийде з ладуAttributeError: 'set' object has no attribute '__dict__'
anatoly techtonik

23

Для цього можна скористатися функцією "dir ()".

>>> import sys
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdo
t__', '_current_frames', '_getframe', 'api_version', 'argv', 'builtin_module_names', 'byteorder
, 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'exc_clear', 'exc_info'
 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'getcheckinterval', 'getdefault
ncoding', 'getfilesystemencoding', 'getrecursionlimit', 'getrefcount', 'getwindowsversion', 'he
version', 'maxint', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_
ache', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit
, 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoption
', 'winver']
>>>

Ще одна корисна особливість - допомога.

>>> help(sys)
Help on built-in module sys:

NAME
    sys

FILE
    (built-in)

MODULE DOCS
    http://www.python.org/doc/current/lib/module-sys.html

DESCRIPTION
    This module provides access to some objects used or maintained by the
    interpreter and to functions that interact strongly with the interpreter.

    Dynamic objects:

    argv -- command line arguments; argv[0] is the script pathname if known

22

Для друку поточного стану об'єкта ви можете:

>>> obj # in an interpreter

або

print repr(obj) # in a script

або

print obj

Для ваших класів визначте __str__або __repr__методи. З документації Python :

__repr__(self)Викликається repr()вбудованою функцією та перетвореннями рядків (зворотні лапки) для обчислення "офіційного" рядкового представлення об'єкта. Якщо це взагалі можливо, це повинно виглядати як дійсне вираження Python, яке може бути використане для відтворення об'єкта з тим же значенням (з урахуванням відповідного середовища). Якщо це неможливо, слід повернути рядок форми "<... деякий корисний опис ...>". Повернене значення повинно бути об’єктом рядка. Якщо клас визначає repr (), але ні __str__(), він __repr__()також використовується, коли потрібно "неформальне" рядкове представлення екземплярів цього класу. Зазвичай це використовується для налагодження, тому важливо, щоб представлення було багатим інформацією та однозначним.

__str__(self)Викликається за допомогою str()вбудованої функції та оператора друку для обчислення "неформального" рядкового подання об'єкта. Це відрізняється __repr__()тим, що воно не повинно бути дійсним виразом Python: замість цього може використовуватися більш зручне або стисле подання. Повернене значення повинно бути об’єктом рядка.


Цей параметр корисний для друку рядків, об'єднаних із вмістом об'єкта:print "DEBUG: object value: " + repr(obj)
AlejandroVD

17

Можливо, варто перевірити -

Чи існує Python, еквівалентний Дані Perl :: Дампер?

Моя рекомендація така -

https://gist.github.com/1071857

Зауважте, що в perl є модуль під назвою Data :: Dumper, який переводить дані об’єкта назад у вихідний код perl (Примітка: він НЕ переводить код назад у джерело, і майже завжди ви не хочете, щоб функції об'єктних методів у висновку). Це можна використовувати для наполегливості, але загальною метою є налагодження.

Існує ряд речей, яких стандартний pprint python не вдається досягти, зокрема, він просто припиняє спадати, коли бачить екземпляр об'єкта і дає вам внутрішній шістнадцятковий вказівник об'єкта (помилково, цей вказівник не є цілою великою користю шлях). Тож у двох словах, python - це вся ця велика об'єктно-орієнтована парадигма, але інструменти, які ви вийдете з коробки, призначені для роботи з чимось, крім предметів.

Perl Data :: Dumper дозволяє контролювати, наскільки глибоко ви хочете пройти, а також виявляє кругові пов'язані структури (це дійсно важливо). Цей процес принципово простіше досягти в перл, оскільки об'єкти не мають особливої ​​магії поза їх благом (загальновизнаний процес).


Це має бути піп і деб не лише суть!
фобій

2
> Отже, у двох словах, python - це вся ця велика об'єктно-орієнтована парадигма, але інструменти, які ви вийдете з коробки, призначені для роботи з чимось, крім предметів ... Досить твердження, коли єдиним прикладом, який ви надаєте, є модуль другорядного значення.
memeplex

@memeplex, де сказано, що python - це все про OOP?
Пітер Вуд

Гаразд, це просто говорить, що це все про цей великий OOP, мій поганий.
memeplex

13

Я рекомендую використовувати help(your_object).

help(dir)

 If called without an argument, return the names in the current scope.
 Else, return an alphabetized list of names comprising (some of) the attributes
 of the given object, and of attributes reachable from it.
 If the object supplies a method named __dir__, it will be used; otherwise
 the default dir() logic is used and returns:
 for a module object: the module's attributes.
 for a class object:  its attributes, and recursively the attributes
 of its bases.
 for any other object: its attributes, its class's attributes, and
 recursively the attributes of its class's base classes.

help(vars)

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

О, чоловіче, +100500
Кірбі

12

У більшості випадків ви користуєтесь інформацією, яку ви хочете , __dict__або dir()отримаєте її. Якщо вам знадобиться більше деталей, стандартна бібліотека включає модуль перевірки , який дозволяє отримати вражаючу кількість деталей. Деякі з реальних помилок інформації включають:

  • назви функцій та параметри методу
  • ієрархії класів
  • вихідний код реалізації функцій / об'єктів класу
  • локальні змінні поза рамним об'єктом

Якщо ви просто шукаєте «що значення атрибутів у мого об'єкта є?», То dir()і __dict__, ймовірно , досить. Якщо ви дійсно хочете зануритися в поточний стан довільних об'єктів (маючи на увазі, що в python майже все є об'єктом), тоді inspectце варто врахувати.


Використовуйте своє пояснення щодо перевірки, щоб покращити найбільш повну відповідь. Сподіваюся, що з вами все нормально.
Фернандо Сесар

9

Чи є вбудована функція для друку всіх поточних властивостей та значень об’єкта?

Ні. Найбільш схвалена відповідь виключає деякі види атрибутів, і прийнята відповідь показує, як отримати всі атрибути, включаючи методи та частини непублічних api. Але немає хорошої повноцінної вбудованої функції для цього.

Таким чином, короткий наслідок полягає в тому, що ви можете написати свій власний, але він буде обчислювати властивості та інші обчислені дескриптори даних, що входять до загальнодоступного API, і ви, можливо, не хочете цього:

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

Проблеми з іншими відповідями

Слідкуйте за застосуванням на даний момент найвищої відповіді в класі з безліччю різних типів даних:

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

тільки відбитки:

{'baz': 'baz'}

Бо vars тільки повертає__dict__ об'єкт, а це не копія, тож якщо ви модифікуєте дікт, повернений vars, ви також змінюєте __dict__сам об'єкт.

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

повертає:

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

- що погано, тому що quux - це властивість, яку ми не повинні встановлювати і не повинні знаходитись у просторі імен ...

Застосування порад у прийнятій наразі відповіді (та інших) не набагато краще:

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

Як ми бачимо, dirтільки повертається всі (фактично лише більшість) імен, пов’язаних із об’єктом.

inspect.getmembers, згадане в коментарях, аналогічно хибно - воно повертає всі назви та значення.

З класу

Під час викладання я моїх учнів створює функцію, яка забезпечує семантично відкритий API об’єкта:

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

Ми можемо розширити це, щоб надати копію семантичного простору імен об’єкта, але нам потрібно виключити __slots__, які не призначені, і якщо ми сприймаємо запит на "поточні властивості" серйозно, нам потрібно виключити обчислені властивості (як вони можуть стати дорогими, і їх можна інтерпретувати як не "поточні"):

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

А тепер ми не обчислюємо та не показуємо властивість, quux:

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

Коваджі

Але, можливо, ми знаємо, що наші властивості недешеві. Ми, можливо, захочемо змінити логіку і включити їх. І, можливо, ми хочемо замість цього виключити інші власні дескриптори даних.

Тоді нам потрібно додатково налаштувати цю функцію. І тому є сенс, що ми не можемо мати вбудованої функції, яка магічно точно знає, що ми хочемо, і забезпечує це. Це функціонал, який нам потрібно створити самостійно.

Висновок

Не існує вбудованої функції, яка б це робила, і ви повинні робити те, що найбільш семантично відповідає вашій ситуації.


Є додаткові близькі дужки після FunctionType. Але дуже корисно - дякую!
nealmcb

@nealmcb дякую, я думаю, що я це отримав. Радий бути корисним! :)
Аарон Холл

7

Приклад метапрограмування Скидання об'єкта магією :

$ cat dump.py
#!/usr/bin/python
import sys
if len(sys.argv) > 2:
    module, metaklass  = sys.argv[1:3]
    m = __import__(module, globals(), locals(), [metaklass])
    __metaclass__ = getattr(m, metaklass)

class Data:
    def __init__(self):
        self.num = 38
        self.lst = ['a','b','c']
        self.str = 'spam'
    dumps   = lambda self: repr(self)
    __str__ = lambda self: self.dumps()

data = Data()
print data

Без аргументів:

$ python dump.py
<__main__.Data instance at 0x00A052D8>

З утилями Gnosis :

$ python dump.py gnosis.magic MetaXMLPickler
<?xml version="1.0"?>
<!DOCTYPE PyObject SYSTEM "PyObjects.dtd">
<PyObject module="__main__" class="Data" id="11038416">
<attr name="lst" type="list" id="11196136" >
  <item type="string" value="a" />
  <item type="string" value="b" />
  <item type="string" value="c" />
</attr>
<attr name="num" type="numeric" value="38" />
<attr name="str" type="string" value="spam" />
</PyObject>

Це трохи застаріло, але все ще працює.


6

Якщо ви використовуєте це для налагодження, і ви просто хочете рекурсивного скидання всього, прийнята відповідь незадовільна, оскільки це вимагає, щоб ваші класи вже мали хороші __str__реалізації. Якщо це не так, це працює набагато краще:

import json
print(json.dumps(YOUR_OBJECT, 
                 default=lambda obj: vars(obj),
                 indent=1))

це не спрацювало на python 3. Довелося встановити pymongo і зробити це відповідно до відповіді @Clark
Tim Ogilvy

як і у багатьох інших відповідей тутTypeError: vars() argument must have __dict__ attribute
пограбувати

6

Спробуйте ppretty

from ppretty import ppretty


class A(object):
    s = 5

    def __init__(self):
        self._p = 8

    @property
    def foo(self):
        return range(10)


print ppretty(A(), show_protected=True, show_static=True, show_properties=True)

Вихід:

__main__.A(_p = 8, foo = [0, 1, ..., 8, 9], s = 5)

саме те, що я шукав для швидкої налагодження :), чудова знахідка!
Йосиф Астрахан

трохи підказки додайте глибину = 6 (або як би далеко вам не потрібно) як один з параметрів для неї, і деталі рекурсії можуть піти далі :). Одне з речей, що мені подобається, як він друкує списки, це те, що він показує перші 2 цілі та останні 2 записи, щоб ви знали, що це працює
Джозеф Астрахан

4
from pprint import pprint

def print_r(the_object):
    print ("CLASS: ", the_object.__class__.__name__, " (BASE CLASS: ", the_object.__class__.__bases__,")")
    pprint(vars(the_object))

4

Це виводить весь вміст об'єкта рекурсивно у форматі json або yaml з відступом:

import jsonpickle # pip install jsonpickle
import json
import yaml # pip install pyyaml

serialized = jsonpickle.encode(obj, max_depth=2) # max_depth is optional
print json.dumps(json.loads(serialized), indent=4)
print yaml.dump(yaml.load(serialized), indent=4)

4

Я підтримав відповідь, що згадує лише pprint. Щоб було зрозуміло, якщо ви хочете бачити всі значення в складному структурі даних, тоді зробіть щось на кшталт:

from pprint import pprint
pprint(my_var)

Там, де мій_вар - ваша змінна особа . Коли я використав, pprint(vars(my_var))я нічого не отримав, а інші відповіді тут не допомогли, або метод виглядав надмірно довго. До речі, в моєму конкретному випадку код, який я перевіряв, мав словник словників.

Варто зазначити, що з деякими спеціальними класами ви можете просто закінчитись із недоброзичливим <someobject.ExampleClass object at 0x7f739267f400>видом. У такому випадку вам, можливо, доведеться реалізувати __str__метод або спробувати деякі інші рішення. Я все одно хотів би знайти щось просте, яке працює у всіх сценаріях, без сторонніх бібліотек.


3
> з деякими спеціальними класами ... Ось чому я не шанувальник пітона. Речі "інколи" працюють, а "іноді" ні
AlxVallejo

3

Мені потрібно було надрукувати інформацію DEBUG у деяких журналах, і я не зміг використати pprint, оскільки це порушило б його. Натомість я це зробив і отримав практично те саме.

DO = DemoObject()

itemDir = DO.__dict__

for i in itemDir:
    print '{0}  :  {1}'.format(i, itemDir[i])

3

Щоб скинути "myObject":

from bson import json_util
import json

print(json.dumps(myObject, default=json_util.default, sort_keys=True, indent=4, separators=(',', ': ')))

Я спробував vars () та dir (); обидва не змогли за те, що я шукав. vars () не працював, тому що в об'єкта не було __dict__ (виключення.TypeError: аргумент vars () повинен мати атрибут __dict__). dir () - це не те, що я шукав: це лише перелік імен полів, не дає значень чи структури об'єкта.

Я думаю, що json.dumps () буде працювати для більшості об'єктів без типового = json_util.default, але у мене було поле дати в об’єкті, тому стандартний серіалізатор json не вдався. Див. Як подолати "datetime.datetime не JSON serializable" у python?


Гаразд, так, щоб використовувати його, довелося встановити пімонго.
Тім Огілві

3

Чому б не щось просте:

for key,value in obj.__dict__.iteritems():
    print key,value

Чи не повинно бути це for key,value in obj.__dict__.iteritems(): print key,value?
Раз

2

pprint містить «гарний принтер» для створення естетичних зображень вашої структури даних. Форматор створює уявлення про структуру даних, які можна правильно проаналізувати інтерпретатором, а також легко читати людині. Якщо можливо, висновок зберігається в одному рядку і відступається при розділенні на кілька рядків.


2

Просто спробуйте звуковий сигнал .

Це допоможе вам не тільки з друком змінних об'єктів, але і з прекрасним виведенням, як це:

class(NormalClassNewStyle):
  dicts: {
  },
  lists: [],
  static_props: 1,
  tupl: (1, 2)

1
Схоже, цей модуль вже не підтримується і має ряд відкритих проблем. Швидше скористайтеся ppretty
Wavesailor

1

Для всіх, хто бореться

  • vars() не повертаючи всіх атрибутів.
  • dir() не повертає значення атрибутів.

Наступний код друкує всі атрибути objз їх значеннями:

for attr in dir(obj):
        try:
            print("obj.{} = {}".format(attr, getattr(obj, attr)))
        except AttributeError:
            print("obj.{} = ?".format(attr))

не отримую помилки, але не рекурсивні так просто отримати багато шестигранних адрес
грабують

0

Ви можете спробувати панель інструментів налагодження Flask.
https://pypi.python.org/pypi/Flask-DebugToolbar

from flask import Flask
from flask_debugtoolbar import DebugToolbarExtension

app = Flask(__name__)

# the toolbar is only enabled in debug mode:
app.debug = True

# set a 'SECRET_KEY' to enable the Flask session cookies
app.config['SECRET_KEY'] = '<replace with a secret key>'

toolbar = DebugToolbarExtension(app)

0

Мені подобається працювати з вбудованими типами клавіш або значень об'єкта python .

Для атрибутів незалежно від методів чи змінних:

o.keys()

Для значень цих атрибутів:

o.values()

0

Це працює незалежно від того, як визначені ваші змінні в класі, усередині __init__ або зовні.

your_obj = YourObj()
attrs_with_value = {attr: getattr(your_obj, attr) for attr in dir(your_obj)}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.