Since everything in Python is an object and objects have attributes (fields and methods), it’s natural to write programs that can inspect what kind of attributes an object has. For example, a Python program could open a socket on the server and it accepts Python scripts sent over the network from a client machine. Upon receiving a new script, the server-side Python program can inspect or more precisely introspect objects, modules, and functions in the new script to decide how to perform the function, log the result, and various useful tasks.
hasattr vs. try-except
There’re two ways to check if a Python object has an attribute or not. The first way is to call the built-in function
hasattr(object, name), which returns
True if the string
name is the name of one of the
False if not. The second way is to
try to access an attribute in an
object and perform some other function if an
AttributeError was raised.
>>> hasattr('abc', 'upper') True >>> hasattr('abc', 'lower') True >>> hasattr('abc', 'convert') False
>>> try: ... 'abc'.upper() ... except AttributeError: ... print("abc does not have attribute 'upper'") ... 'ABC' >>> try: ... 'abc'.convert() ... except AttributeError: ... print("abc does not have attribute 'convert'") ... abc does not have attribute 'convert'
What’s the difference between these two styles?
hasattr is often referred as a Python programming style called “Look Before You Leap” (LBYL) because you check whether an object has an attribute or not before you access it. While
try-except is referred as “Easier to Ask for Forgiveness than Permission” (EAFP) because you
try the attribute access first and ask for forgiveness in the
except block instead of asking for permission like
Which way is better, then? Well, both doctrines have loyal supporters and both styles seem to be well-versed to deal with any real-world programming challenge. Sometimes, it makes sense to use LBYL if you want to make sure an attribute definitely exists and stop execution if it doesn’t. For example, you know for certain at a point in the program that a passed-in
object should have a valid file pointer attribute on which the following code can work. On the other hand, it also makes sense to use EAFP if you know an attribute might not exist at some point during the program’s execution. For example, a music player could not guarantee a MP3 file is always on-disk at the same location, because it might be deleted, modified, or moved by the user at any time. In this case, the music player can
try to access the MP3 file first and notify the user that the file does not exist in an
hasattr vs __dict__
hasattr is a built-in function that is designed to check if an attribute exists in an object, sometimes it might be more accurate to check an object’s
__dict__ for an attribute’s existence instead due to the fact that
hasattr does not care about the reason why an attribute’s attached to an object while you may want to know why an attribute’s attached to an object. For example, an attribute might be attached to an object due to its parent class instead of the object itself.
>>> class A(object): ... foo = 1 ... >>> class B(A): ... pass ... >>> b = B() >>> hasattr(b, 'foo') True >>> 'foo' in b.__dict__ False
In the previous code, since class
B is a subclass of class
B also has the attribute “foo”. However, because “foo” is inherited from
B.__dict__ does not contain it. Sometimes, it might be crucial to know whether an attribute comes from an object’s class itself or from the objects’ superclass.
Tips and Suggestions
hasattrfollows the duck-typing principle in Python:
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.
So, most of the time you want to use
hasattrto check if an attribute exists in an object.
__dict__have their own use cases which are actually quite narrow compared to
hasattr. So, it is beneficial to keep these special use cases in the back of your head so that you will recognize them during coding and use the proper idioms accordingly.
Once you’ve learnt how to check if an object has an attribute in Python, checkout how to get an attribute from an object.