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
Is _Init_.Py Not Required for Packages in Python 3.3+
Using Property() on Classmethods
CSV in Python Adding an Extra Carriage Return, on Windows
Converting a String Representation of a List into an Actual List Object
After Conda Update, Python Kernel Crashes When Matplotlib Is Used
Extracting Extension from Filename in Python
Why Does Id({}) == Id({}) and Id([]) == Id([]) in Cpython
What Are "Named Tuples" in Python
Pg_Config Executable Not Found
Formatting Floats Without Trailing Zeros
How to Determine a Python Variable's Type
What Are the Differences Between Numpy Arrays and Matrices? Which One Should I Use
Proper Name for Python * Operator
Can't Set Attributes on Instance of "Object" Class
How to Change the X Axis in Matplotlib So There Is No White Space
How to Direct Output to a File When There Are Utf-8 Characters