Search code examples
pythonjsondjangopretty-print

python : object.__dict__ not showing all attributes


I am trying to print all the attibutes of an object. The purpose is mainly for debugging.

I am using the following code:

import json
print(json.dumps(object.__dict__), indent=4, sort_keys=True, default=str))

It prints the attibutes of the object.

But i was checking the list of all properties of the object using

dir(object)

I found that __dict__ does not show some properties at all which are listed by dir().

I thought of using dir(object) but it only a list of properties without attributes.

So i think:

`__dict__` has `incomplete` properties but with attirbutes

`dir()` has complete list of properties but no attibutes

So what is the best way to get a full dictionary of a attibutes of an object so that i can pretty print and see using json.dumps

EXAMPLE

I am working in a django project. And this is with related to db connection

so the example is of a variable names db_con which is of the following object

<django.db.backends.postgresql.base.DatabaseWrapper object at 0x7f29dee47a58>

__dict__ way

import json
print(json.dumps(db_con.__dict__), indent=4, sort_keys=True, default=str))

The output is

{
    "_thread_ident": ATTRIBUTE_VALUE
    "_thread_sharing_count": ATTRIBUTE_VALUE
    "_thread_sharing_lock": ATTRIBUTE_VALUE
    "alias": ATTRIBUTE_VALUE
    "autocommit": ATTRIBUTE_VALUE
    "client": ATTRIBUTE_VALUE
    "close_at": ATTRIBUTE_VALUE
    "closed_in_transaction": ATTRIBUTE_VALUE
    "commit_on_exit": ATTRIBUTE_VALUE
    "connection": ATTRIBUTE_VALUE
    "creation": ATTRIBUTE_VALUE
    "errors_occurred": ATTRIBUTE_VALUE
    "execute_wrappers": ATTRIBUTE_VALUE
    "features": ATTRIBUTE_VALUE
    "force_debug_cursor": ATTRIBUTE_VALUE
    "in_atomic_block": ATTRIBUTE_VALUE
    "introspection": ATTRIBUTE_VALUE
    "isolation_level": ATTRIBUTE_VALUE
    "needs_rollback": ATTRIBUTE_VALUE
    "ops": ATTRIBUTE_VALUE
    "queries_log": ATTRIBUTE_VALUE
    "run_commit_hooks_on_set_autocommit_on": ATTRIBUTE_VALUE
    "run_on_commit": ATTRIBUTE_VALUE
    "savepoint_ids": ATTRIBUTE_VALUE
    "savepoint_state": ATTRIBUTE_VALUE
    "settings_dict": ATTRIBUTE_VALUE
        "ATOMIC_REQUESTS": ATTRIBUTE_VALUE
        "AUTOCOMMIT": ATTRIBUTE_VALUE
        "CONN_MAX_AGE": ATTRIBUTE_VALUE
        "ENGINE": ATTRIBUTE_VALUE
        "HOST": ATTRIBUTE_VALUE
        "NAME": ATTRIBUTE_VALUE
        "OPTIONS": ATTRIBUTE_VALUE
        "PASSWORD": ATTRIBUTE_VALUE
        "PORT": ATTRIBUTE_VALUE
        "TEST": ATTRIBUTE_VALUE
            "CHARSET": ATTRIBUTE_VALUE
            "COLLATION": ATTRIBUTE_VALUE
            "MIRROR": ATTRIBUTE_VALUE
            "NAME": ATTRIBUTE_VALUE
        },
        "TIME_ZONE": ATTRIBUTE_VALUE
        "USER": ATTRIBUTE_VALUE
    },
    "timezone": ATTRIBUTE_VALUE
    "timezone_name": ATTRIBUTE_VALUE
    "validation": ATTRIBUTE_VALUE
    "wrap_database_errors": ATTRIBUTE_VALUE

And the attibutes using dir()

print(json.dumps(dir(db_con), indent=4, sort_keys=True, default=str))
[
    "Database",
    "SchemaEditorClass",
    "__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__",
    "__str__",
    "__subclasshook__",
    "__weakref__",
    "_close",
    "_commit",
    "_cursor",
    "_named_cursor_idx",
    "_nodb_connection",
    "_prepare_cursor",
    "_rollback",
    "_savepoint",
    "_savepoint_allowed",
    "_savepoint_commit",
    "_savepoint_rollback",
    "_set_autocommit",
    "_thread_ident",
    "_thread_sharing_count",
    "_thread_sharing_lock",
    "alias",
    "allow_thread_sharing",
    "autocommit",
    "check_constraints",
    "check_settings",
    "chunked_cursor",
    "clean_savepoints",
    "client",
    "client_class",
    "close",
    "close_at",
    "close_if_unusable_or_obsolete",
    "closed_in_transaction",
    "commit",
    "commit_on_exit",
    "connect",
    "connection",
    "constraint_checks_disabled",
    "copy",
    "create_cursor",
    "creation",
    "creation_class",
    "cursor",
    "data_type_check_constraints",
    "data_types",
    "data_types_suffix",
    "dec_thread_sharing",
    "disable_constraint_checking",
    "display_name",
    "enable_constraint_checking",
    "ensure_connection",
    "ensure_timezone",
    "errors_occurred",
    "execute_wrapper",
    "execute_wrappers",
    "features",
    "features_class",
    "force_debug_cursor",
    "get_autocommit",
    "get_connection_params",
    "get_new_connection",
    "get_rollback",
    "in_atomic_block",
    "inc_thread_sharing",
    "init_connection_state",
    "introspection",
    "introspection_class",
    "is_usable",
    "isolation_level",
    "make_cursor",
    "make_debug_cursor",
    "needs_rollback",
    "on_commit",
    "operators",
    "ops",
    "ops_class",
    "pattern_esc",
    "pattern_ops",
    "pg_version",
    "prepare_database",
    "queries",
    "queries_limit",
    "queries_log",
    "queries_logged",
    "rollback",
    "run_and_clear_commit_hooks",
    "run_commit_hooks_on_set_autocommit_on",
    "run_on_commit",
    "savepoint",
    "savepoint_commit",
    "savepoint_ids",
    "savepoint_rollback",
    "savepoint_state",
    "schema_editor",
    "set_autocommit",
    "set_rollback",
    "settings_dict",
    "temporary_connection",
    "timezone",
    "timezone_name",
    "validate_no_atomic_block",
    "validate_no_broken_transaction",
    "validate_thread_sharing",
    "validation",
    "validation_class",
    "vendor",
    "wrap_database_errors"
]

I want to use db_con['queries'] to get a the list of queries but its not shown in __dict__ and can be confusing if dont know db_con['queries'] exists which i came to know through dir()

Thirdparty Solution i found:

I am using runserver_plus

python manage.py runserver_plus

Runserver_plus: Django-extensions includes a management command (runserver_plus) to start the Werkzeug interactive debugger with your project

Werkzeug: Werkzeug is a WSGI utility library for Python. Beyond others, it includes an interactive debugger - what this means is that when your python application throws an exception, Werkzeug will display the exception stacktrace in the browser (that’s not a big deal) and allow you to write python commands interactively wherever you want in that stacktrace (that’s the important stuff).

whereever i want to check a variable i add a=+1 after that so that it throws an exception (UnboundLocalError: local variable 'a' referenced before assignment) then i can open an interactive console there and check the object attibutes using dump(var) which shows all the attributes. Currently i check the attributes using that.

I want to do it using regular python way.


Solution

  • obj.__dict__ is the storage for instance attributes (for dict-based classes - some are slot-based and some (C coded) are just, well, what they are xD). Other "properties" (caveat: in Python, 'property' is also the name of a builtin class that provides generic support for computed attributes) that you'll find using dir(obj) belong either to the class or one of it's parent, so they are obviously not in obj.__dict__.

    Also and FWIW, dir() doesn't necessarily lists all of an object's properties :

    Help on built-in function dir in module builtin:

    dir(...) dir([object]) -> list of strings

    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.
    

    If you really want to retrieve all properties values, you can use [getattr][1](obj, name[, default]) ie:

    everything = {k: getattr(obj, k) for k in dir(obj)}
    

    BUT you won't be able to serialize this to json - functions / methods, properties (the Python builtin type...), classes (the object's class) and quite a few other things are not json-serializable (how would you serialize a function ?)

    Also, you may have classes implementing __getattr__ (usually for dynamic delegation), so even with dir there might be properties (in the generic meaning) that are accessible on your object but that just can't be listed via inspection.

    So what is the best way to get a full dictionary of a attibutes of an object so that i can pretty print

    Something like inspect.getmembers(obj) comes to mind. But you may find out that obj.__dict__ is usually the most useful part already.

    and see using json.dumps

    Well, cf above...

    I want to use db_con['queries'] to get a the list of queries but its not shown in dict and can be confusing if dont know db_con['queries'] exists which i came to know through dir()

    if you're in the python shell, you can just use the builtin help system.