Before we go any further, remember one simple thing, the purpose of introspection is to examine, whereas reflection can both example and modify.

In other words, introspection is passive, and reflection is active.

And remember, everything in Python is an object.

Introspection

Introspection is also called ‘type introspection’, it’s the ability to exam something, typically an object, at runtime. With introspection, everything about an object is exposed. Such as, what it is, what attributes it has, and etc.

You may wonder, “why am I seeing all the dunder attributes in the list, besides ‘foo’ and ‘get_foo’ that I have defined?”

This is because everything in python is an object. This means all objects are inherited from the builtin object class, it doesn’t matter if it’s the ones you defined or not.

Example 2: Type checking

Type checking can vary in different ways, like so:

# Check the type/class of an object
type(my_object)
my_object.__class__
# check is the object is a specific type or class
isinstance(my_str, str)
# check if an object's class is a subclass of a parent class
issubclass(my_object.__class__, ParentClass)

Important: I would really be careful with isinstance(), it does not work as expected all the time. If the first argument (the object passed in)’s class is an extended class of the second argument (the class passed in), this would always evaluate to True.

I have encountered this while making a function for logging to ensure no duplicated handlers. However, since logging.FileHandler is a child class of logging.StreamHandler, so isninstance() will return True:

Other than the examples above, there are quite a lot more you can do with introspection in Python. I would highly suggest looking into the inspect module. This module provides functionalities to check if an object is a class, a method, a module, or a function.

inspect.isclass(), inspect.ismethod(), inspect.isfunction() are very useful for decorators, which I won’t cover in this article.

Here is a rather silly example to detect whether the decorated object is a class or a function:

Don’t worry if you don’t exactly understand how this works for now, since this article isn’t about decorators. If you do have questions, feel free to message me or leave a comment.

Moving on.

Reflection

In comparison to introspection, reflection is much more powerful. As I had mentioned earlier: Introspection is passive, the purpose is to examine; Reflection is active, and it’s not only able examine, but also to modify.

Concretely, reflection means the ability of a program to examine and modify its own structure and behavior at runtime. For example, setting an attribute of a module at runtime, as I have briefly mentioned in Dynamic Import in Python 3, I will go in more depth in the first example.

Example 1: Setting Attributes Dynamically

Supposedly, I have an empty python file, and I want to have all the environment variables as attributes of this module. let’s call this file envs.py.

As you can see, here we create an object of GreetMe, and called to the methods ‘hello(), bye() and nice_to_meet_you()’, and none of these methods are defined with in the GreetMe class.

We are able to call these methods is because of the __getattr__() method implemented in the class. Python calls __getattr__() whenever a undefined method is being accessed. In our example, only the methods names within the allowed list can be called.

Closing Thoughts

Both introspection and reflection are very powerful concepts, and Python has strong support for them. You can certainly gain a great amount of flexibility and control once you get a hang of them. One thing to keep in mind is that reflection can fall into the category of implicity very quickly.