1. Application Scenarios
- Control the program’s runtime flow through a configuration file. What a configuration file usually holds is a string, not an object.
- When debugging a program, inspect all the attribute values of an object.
- Dynamic module import.
For the first scenario, reflection is the widely adopted approach. Many Java frameworks use the reflection mechanism, and Django, a Web framework implemented in Python, applies it too — URL routing, for example. In the second scenario, manually adding output for an object’s attributes is extremely tedious and still incomplete. Here you can use dir(object) to list all attributes and then use reflection to access them. The third scenario can also be achieved through reflection.
2. Python’s Reflection
Through reflection, a string can be associated with an object’s attribute. With dir(object) you can view the attribute list of an object.
| |
2.1 getattr
Form: getattr(object, ’name’, ‘default’)
Description: if an attribute or method named name exists, return that attribute or method; otherwise return the default.
2.2 hasattr
Form: hasattr(object, ’name')
Description: determine whether the object contains an attribute or method named name; return True if it exists, otherwise False. hasattr is implemented by calling getattr(object, ’name’) and checking whether it throws an exception.
2.3 setattr
Form: setattr(object, ’name’, ‘default’)
Description: set the name attribute of the object to default; if the name attribute does not exist, create a new attribute.
2.4 delattr
Form: delattr(object, ’name')
Description: delete the name attribute of the object.
3. How Python Implements Reflection
The globals() function returns a dictionary { key:value }, where key is the name of the object and value is the instance of the object.
| |
After executing import test, you can see that a new test key has been added. You can use this to implement functionality similar to Java’s Class.forName(). But with this approach you must import first, otherwise it throws an exception.
Python provides the __import__(“functionName”) function: pass the argument “functionName” and the functionName module is imported. Combine it with the getattr function to make the relevant call.
4. Why Not Just Use exec and eval
Those familiar with Python should know that the exec and eval statements can also execute Python statements stored in a string or a file.
For example:
| |
So why use reflection at all? exec and eval can achieve the same functionality, but reflection is a programming approach, an embodiment of design patterns. Reflection embodies the software design ideas of high cohesion and low coupling, and cannot simply be replaced by a function that executes a string.
