Scott's Recipes Logo

Dynamic Method Introspection in Ruby Versus Python

One of the features in Ruby that I use most frequently is dynamically getting the methods (aka introspection) for an object when I’m doing exploratory programming in a REPL:

    (Rails.cache.methods - Object.methods).sort
    [
        [ 0] :cleanup,
        [ 1] :clear,
        [ 2] :decrement,
        [ 3] :delete,
        [ 4] :delete_matched,
        [ 5] :delete_multi,
        [ 6] :exist?,
        [ 7] :fetch,
        [ 8] :fetch_multi,
        [ 9] :increment,
        [10] :logger,
        [11] :logger=,
        [12] :middleware,
        [13] :mute,
        [14] :new_entry,
        [15] :options,
        [16] :read,
        [17] :read_multi,
        [18] :silence,
        [19] :silence!,
        [20] :silence?,
        [21] :with_local_cache,
        [22] :write,
        [23] :write_multi
    ]

The python equivalent to this is:

    -> db_conn.execute(sql_statement)
    (Pdb) print(dir(db_conn))
    ['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_cursor', '_prepare_cursor', '_rollback', '_savepoint', '_savepoint_allowed', 
    '_savepoint_commit', '_savepoint_rollback', '_set_autocommit', '_thread_ident', 
    '_thread_sharing_count', '_thread_sharing_lock', 'alias', 'allow_thread_sharing', 
    'atomic_blocks', 'autocommit', 'check_constraints', 'check_database_version_supported', 
    'check_settings', 'chunked_cursor', 'clean_savepoints', 'client', 'client_class', 'close', 
    'close_at', 'close_if_health_check_failed', '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_database_version', 'get_new_connection', 'get_rollback', 'health_check_done', 
    'health_check_enabled', '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', 
    'tzinfo_factory', 'validate_no_atomic_block', 'validate_no_broken_transaction', 
    'validate_thread_sharing', 'validation', 'validation_class', 'vendor', 'wrap_database_errors']