Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which is the best way to check for the existence of an attribute? [duplicate]

Which is a better way to check for the existence of an attribute?

Jarret Hardie provided this answer:

if hasattr(a, 'property'):     a.property 

I see that it can also be done this way:

if 'property' in a.__dict__:     a.property 

Is one approach typically used more than others?

like image 528
Andrew Halloran Avatar asked Mar 17 '12 09:03

Andrew Halloran


People also ask

How do you check if an object has an attribute?

We can use hasattr() function to find if a python object obj has a certain attribute or property. hasattr(obj, 'attribute'): The convention in python is that, if the property is likely to be there, simply call it and catch it with a try/except block.

How do you use Hasattr in python?

Python hasattr() FunctionThe hasattr() function returns True if the specified object has the specified attribute, otherwise False .

How do I see all the attributes of an object in python?

To list all the attributes of an object, use the built-in dir() function. It returns a long list of attribute names, that is, method and variable names of the object.

What is Getattr python?

Python | getattr() method Python getattr() function is used to access the attribute value of an object and also gives an option of executing the default value in case of unavailability of the key. Syntax : getattr(obj, key, def) Parameters : obj : The object whose attributes need to be processed.


2 Answers

There is no "best" way, because you are never just checking to see if an attribute exists; it is always a part of some larger program. There are several correct ways and one notable incorrect way.

The wrong way

if 'property' in a.__dict__:     a.property 

Here is a demonstration which shows this technique failing:

class A(object):     @property     def prop(self):         return 3  a = A() print "'prop' in a.__dict__ =", 'prop' in a.__dict__ print "hasattr(a, 'prop') =", hasattr(a, 'prop') print "a.prop =", a.prop 

Output:

 'prop' in a.__dict__ = False hasattr(a, 'prop') = True a.prop = 3 

Most of the time, you don't want to mess with __dict__. It's a special attribute for doing special things, and checking to see if an attribute exists is fairly mundane.

The EAFP way

A common idiom in Python is "easier to ask for forgiveness than permission", or EAFP for short. You will see lots of Python code that uses this idiom, and not just for checking attribute existence.

# Cached attribute try:     big_object = self.big_object     # or getattr(self, 'big_object') except AttributeError:     # Creating the Big Object takes five days     # and three hundred pounds of over-ripe melons.     big_object = CreateBigObject()     self.big_object = big_object big_object.do_something() 

Note that this is exactly the same idiom for opening a file that may not exist.

try:     f = open('some_file', 'r') except IOError as ex:     if ex.errno != errno.ENOENT:         raise     # it doesn't exist else:     # it does and it's open 

Also, for converting strings to integers.

try:     i = int(s) except ValueError:     print "Not an integer! Please try again."     sys.exit(1) 

Even importing optional modules...

try:     import readline except ImportError:     pass 

The LBYL way

The hasattr method, of course, works too. This technique is called "look before you leap", or LBYL for short.

# Cached attribute if not hasattr(self, 'big_object'):     big_object = CreateBigObject()     self.big_object = CreateBigObject() big_object.do_something() 

(The hasattr builtin actually behaves strangely in Python versions prior to 3.2 with regard to exceptions -- it will catch exceptions that it shouldn't -- but this is probably irrelevant, since such exceptions are unlikely. The hasattr technique is also slower than try/except, but you don't call it often enough to care and the difference isn't very big. Finally, hasattr isn't atomic so it could throw AttributeError if another thread deletes the attribute, but this is a far-fetched scenario and you'll need to be very careful around threads anyway. I don't consider any of these three differences to be worth worrying about.)

Using hasattr is much simpler than try/except, as long as all you need to know is whether the attribute exists. The big issue for me is that the LBYL technique looks "strange", since as a Python programmer I'm more used to reading the EAFP technique. If you rewrite the above examples so that they use the LBYL style, you get code that is either clumsy, outright incorrect, or too difficult to write.

# Seems rather fragile... if re.match('^(:?0|-?[1-9][0-9]*)$', s):     i = int(s) else:     print "Not an integer! Please try again."     sys.exit(1) 

And LBYL is sometimes outright incorrect:

if os.path.isfile('some_file'):     # At this point, some other program could     # delete some_file...     f = open('some_file', 'r') 

If you want to write a LBYL function for importing optional modules, be my guest... it sounds like the function would be a total monster.

The getattr way

If you just need a default value, getattr is a shorter version of try/except.

x = getattr(self, 'x', default_value) 

If the default value is expensive to construct, then you'll end up with something like this:

x = getattr(self, 'attr', None) if x is None:     x = CreateDefaultValue()     self.attr = x 

Or if None is a possible value,

sentinel = object()  x = getattr(self, 'attr', sentinel) if x is sentinel:     x = CreateDefaultValue()     self.attr = x 

Conclusion

Internally, the getattr and hasattr builtins just use try/except technique (except written in C). So they all behave the same way where it counts, and picking the right one is due to a matter of circumstances and style.

The try/except EAFP code will always rub some programmers the wrong way, and the hasattr/getattr LBYL code will irk other programmers. They're both correct, and there's often no truly compelling reason to pick one or the other. (Yet other programmers are disgusted that you would consider it normal for an attribute to be undefined, and some programmers are horrified that it's even possible to have an undefined attribute in Python.)

like image 94
Dietrich Epp Avatar answered Sep 26 '22 12:09

Dietrich Epp


hasattr() is the way*.

a.__dict__ is ugly and it doesn't work in many cases. hasattr() actually tries to get attribute and catches AttributeError internally so it works even if you define custom __getattr__() method.

To avoid requesting the attribute twice the third argument for getattr() could be used:

not_exist = object()  # ... attr = getattr(obj, 'attr', not_exist) if attr is not_exist:    do_something_else() else:    do_something(attr) 

You could just use a default value instead of not_exist sentinel if it is more appropriate in your case.

I don't like try: do_something(x.attr) \n except AttributeError: .. it might hide AttributeError inside do_something() function.

*Before Python 3.1 hasattr() suppressed all exceptions (not only AttributeError) if it is not desirable getattr() should be used.

like image 25
jfs Avatar answered Sep 22 '22 12:09

jfs