First: what is an “attribute” in Python? It’s basically just a fancy way of saying that something belongs to another thing (like how a book has a title or an author). In code, we access these attributes using the dot notation for example, `book.title` or `person.name`.
But what if you want to customize attribute access? Maybe you’re writing a debugger tool and need to let users interactively specify which attributes they want to see. Or maybe you have a module with a lot of functions that you only want certain people to be able to use. That’s where Python’s `getattr()` function comes in handy!
Here’s an example: say we have a book object called `b`, and we want to access its title attribute using the dot notation, but for some reason (let’s just pretend) that attribute doesn’t exist. Instead of getting an error message, we can use `getattr()` to retrieve it dynamically like this:
# Here is the context before the script:
# handy!
# Here's an example: say we have a book object called `b`, and we want to access its title attribute using the dot notation, but for some reason (let's just pretend) that attribute doesn't exist. Instead of getting an error message, we can use `getattr()` to retrieve it dynamically like this:
# Here is the script:
# The following script checks if the book object `b` has a title attribute using the `hasattr()` function. If it does, the title is printed using dot notation. If not, a message is printed stating that no title was found for the book object.
# Create a book object
b = Book()
# Check if the book object has a title attribute
if hasattr(b, 'title'):
# If it does, print the title using dot notation
print(b.title)
else:
# If not, print a message stating no title was found
print("No title found for book object.")
# Alternatively, we can use the `getattr()` function to retrieve the title attribute dynamically. If the attribute does not exist, the default value "No title found for book object." is returned.
print(getattr(b, "title", "No title found for book object."))
This is great and all, but what if you want to customize attribute access on a module level? Maybe you have a bunch of functions that are only meant for internal use or should be deprecated. That’s where Python 3.7 comes in with its new `__getattr__()` function!
Here’s an example: let’s say we have a module called `my_module`, and we want to add some custom functionality when someone tries to access an attribute that doesn’t exist. We can do this by adding the following code at the end of our `my_module.py` file:
# This script creates a class called MyModule with a custom __getattr__() function that will be triggered when an attribute is accessed that doesn't exist in the class.
class MyModule(object): # Creates a class called MyModule that inherits from the object class.
def __getattr__(self, name): # Defines the custom __getattr__() function that takes in the attribute name as a parameter.
if name == "deprecated_function": # Checks if the attribute being accessed is "deprecated_function".
print("Warning! The deprecated function '{}' is no longer supported.".format(name)) # Prints a warning message with the name of the deprecated function.
return None # Returns None to prevent an error from being raised.
# Then we can import our module and use it like this:
from my_module import * # Imports all functions and attributes from the my_module module.
print(my_module.some_function()) # Calls the some_function() function from the my_module module.
try:
print(my_module.deprecated_function()) # Tries to call the deprecated_function() function from the my_module module.
except AttributeError: # If an AttributeError is raised (since the function doesn't exist), the following code will be executed.
pass # Does nothing, simply used to handle the AttributeError and prevent it from being raised.
And that’s all there is to it! With `getattr()` and `__getattr__()`, you can customize attribute access in Python with ease, whether on a per-object or module level. Just remember to keep your code simple and straightforward no need for fancy data attributes when plain old variables will do the trick!