How to Know If an Object Has an Attribute in Python

How do I determine if an object has an attribute in Python?

Try hasattr():

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

See zweiterlinde's answer below, who offers good advice about asking forgiveness! A very pythonic approach!

The general practice in python is that, if the property is likely to be there most of the time, simply call it and either let the exception propagate, or trap it with a try/except block. This will likely be faster than hasattr. If the property is likely to not be there most of the time, or you're not sure, using hasattr will probably be faster than repeatedly falling into an exception block.

Does python have a shorthand to check if an object has an attribute?

The Pythonic way is to look out for NameError exception that would be raised when the variable is not defined, the name is not bound to any object to be precise.

So, for example:

try:
foobar
except NameError:
# Do stuffs
print('foobar is not defined')
raise # raise the original exception again, if you want

Names reside in namespaces e.g. local names reside in locals() (dict) namespace, global names reside in globals() (dict) namespace. You can define a function that takes name string and namespace as an argument to check for the existence, here is a hint passing namespace as a dict and catching KeyError:

In [1213]: def is_defined(name, namespace):
...: try:
...: namespace[name]
...: except KeyError:
...: return False
...: return True
...:

In [1214]: is_defined('spamegg', globals())
Out[1214]: False

In [1215]: spamegg = 10

In [1216]: is_defined('spamegg', globals())
Out[1216]: True

On the other hand, if you are looking to get the value of an atrribute string of an object, getattr is the way to go:

getattr(obj, attr)

For example, the following two are equivalent:

obj.foobar
getattr(obj, 'foobar')

Even you can add a default when the object attribute is missing:

getattr(obj, 'foobar', 'spamegg')

The above will output the value obj.foobar, if foobar is missing it would output spamegg.

You might also be interested in hasattr that returns True/False for an attribute existence check, instead of needing to manually handle AttributeError.

How to find out if object has attributes?

The error message is telling you that groupName itself is None.

In which case, there's little point in testing whether it has a particular attribute.

So you probably want something more like:

If groupName is not None:
print groupName.group

Or, if groupName objects may not have a group attribute:

If groupName is not None:
print getattr(groupName, 'group', None)

(Note: the last argument of getattr is a default value that can be anything you want).

Check if an object has an attribute from a list of attributes, and if is found assign it to a variable - dynamic

Make the attributes into a list and iterate through it:

for attr in ['a', 'b', 'c', 'd']:
try:
result = getattr(o, attr)
except AttributeError:
# Try the next one
continue
break
else:
raise ValueError("No attribute found")

Apparently, the list can also be constructed dynamically.

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

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.)

Is there a way to find if a python object has an attribute?

Double underscore variables are name mangled adding the class name in front of the method, so __a becomes _A__a as you rightly identified, hence you get False in the first case.

Similarly you can do hasattr(self, '_'+self.__class__.__name__ + '__a') in the second case

class A :

def __init__(self) :
self.__a = 5

def hasAttr(self) :

attr_name = f'_{self.__class__.__name__}__a'
if hasattr(self, attr_name):
print(True)
else :
print(False)

x = A()
x.hasAttr()

Or you can use EAFP approach to try to access the variable, and print True or False accordingly

class A :

def __init__(self) :
self.__a = 5

def hasAttr(self):

attr_name = f'_{self.__class__.__name__}__a'
try:
getattr(self, attr_name)
print(True)
except:
print(False)

x = A()
x.hasAttr()

The output will be True

Python: How can I check if an attribute of an object is a method or not?

You can use inspect for something like this:

from inspect import ismethod,getmembers

class Example:
def __repr__(self):
return "\n".join("%s: %s" % (k, v) for (k,v) in getmembers(self,lambda x: not ismethod(x)))

def method(self):
return 1

a = Example()
a.foo = 'bar'
print a

This also picks up the double underscore attributes (__module__, __doc__). If you don't want those, you can pretty easily filter them out.

How to know which attribute and object has a specified value

If you are looking for an attribute value within an instance of A, you can simply put all of them in a pool and scan it to fetch a matching object.

So:

class MappingPool:
def __init__(self):
self.pool = []
def add_scannable_object(self, obj):
self.pool.append(obj)
def search(self, some_value):
for obj in self.pool:
for attr in obj.__dict__:
if getattr(obj, attr) == some_value:
return obj

Should return the first object found containing an attribute matching the desired value. I'm limiting the search to instances atrributes and not including class attributes because you seem to only be interested in those. (Those defined in A.__init__.)

To use it:

mapping = MappingPool()
b = B('a','b','c')
c = C('test','d','e')
d = D('f','g','h')
mapping.add_scannable_object(b)
mapping.add_scannable_object(c)
mapping.add_scannable_object(d)
x = mapping.search('test') # x is now an alias to c

Update to react to comments and clarify between attributes and class attributes

You’re are not restricted about the objects you put into the mapping pool. For what it’s worth, you can put anything that has a __dict__ attribute in it. Any class and any instance of any class are suitable. I.e. if in addition to your A, B, C and D classes you define:

class Test:
where_is_it = 5
def __init__(self):
it_is_here = 9

then, you can add any instance of Test to the same MappingPool you used to put b, c, and d as show above. Thus:

mapping = MappingPool()
b = B('a','b','c')
c = C('test','d','e')
d = D('f','g','h')
test = Test()
mapping.add_scannable_object(b)
mapping.add_scannable_object(c)
mapping.add_scannable_object(d)
mapping.add_scannable_object(test)
x = mapping.search(9)
print(x is test) # prints True

What I wanted to warn about when saying that the search is not including class attributes is that, using the setup just above, mapping.search(5) returns None even though test.where_is_it is 5.

This is due to the fact that instance variables and class variables are defined in two different namespaces and using obj.__dict__ returns only the namespace of the instance.

You can convince yourself by typing test.__dict__ which returns {'it_is_here': 9}. So where did the where_is_it attribute go? In the class namespace, since it’s defined at the class level:

>>> test.__class__.__dict__
mappingproxy({'__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None, '__init__': <function Test.__init__ at 0x7f4bf6f09d08>, '__module__': '__main__', 'where_is_it': 5})

Thus if you need to take into account both instance attributes and class attributes of the objects you are scanning, then you need to combine both:

from itertools import chain

for attr in chain(test.__dict__, test.__class__.__dict__):
print(attr)

outputs:

it_is_here
__dict__
__weakref__
__doc__
__init__
__module__
where_is_it

Conclusion, just replace for attr in obj.__dict__: by for attr in chain(obj.__dict__, obj.__class__.__dict__): if you want to support class attributes on top of instances attributes.

Check if list of objects contain an object with a certain attribute value

As you can easily see from the documentation, the any() function short-circuits an returns True as soon as a match has been found.

any(x.name == "t2" for x in l)


Related Topics



Leave a reply



Submit