5.33. Introspection¶
A handful of built-ins let a running program inspect itself – the values it is working with, the namespaces those values live in, and the relationships between classes. Reach for them when you need to make decisions based on what an object actually is, rather than what its caller claims it is.
5.33.1. Identity and hashing¶
id()– a unique integer that identifies an object for as long as it is alive. Two names that bind the same object return the same id; two equal-but-distinct objects do not.
>>> a = [1, 2, 3]
>>> b = a
>>> c = [1, 2, 3]
>>> id(a) == id(b) # same list
True
>>> id(a) == id(c) # equal but distinct
False
The id is not portable across runs and not meaningful beyond “same object or different object.”
hash()– the hash value of an object, the same numberdictandsetuse to look it up. Two equal objects hash to the same value; only hashable types (immutable values, mostly) work at all.
>>> hash("abc") # some integer, build-dependent
-1600925533
>>> hash([1, 2])
TypeError: unhashable type: 'list'
5.33.2. Querying types and callability¶
type()– the exact class of a value.type(x) is intasks “is x exactly an int” (no subclasses);isinstance()is usually what you want instead.isinstance()– “is x an instance of this class, or a subclass of it?” The standard tool for type-based dispatch inside functions.issubclass()– the class-level counterpart. Takes two classes rather than an instance.callable()–Trueif the argument can be called with(). Useful when you receive an argument that may be a function or may be a plain value.
>>> isinstance(3, int)
True
>>> isinstance(True, int) # bool is a subclass of int
True
>>> issubclass(bool, int)
True
>>> callable(len)
True
>>> callable(10)
False
A pattern that uses callable:
def call_or_return(x):
return x() if callable(x) else x
5.33.3. Looking at scopes¶
globals()– the module’s global namespace as adict. Reading from it works; writing to it is real, but doing so outside of REPL exploration makes a program difficult to follow.locals()– the local namespace at the call site. Inside a function it reflects the local variables; modifying the returned dict is not guaranteed to write back into the actual locals (implementation-defined behaviour).
name = "OpenMV"
def f():
x = 10
print(globals()["name"]) # OpenMV
print(locals()) # {'x': 10}
These two are useful for debugging and for tools that need to
discover what is defined. Reach for them sparingly in regular
code – a function that mutates globals() is one of the
hardest things to reason about in Python.
5.33.4. See also¶
dir() and help(), covered in debugging, are the everyday introspection
tools for exploring an unknown object’s surface.