Fenixs
Fenixs

Reputation: 353

hasattr returns attribute error even after exception is captured

Here is my sample code to check if the given attribute is present in the class or not.

class EmpDict:
    def __init__(self, data):
        self.data = data
        try:
            self.first_name = data['first_name']
            self.age        = data['age']
            self.last_name  = data['last_month']
        except:
            pass

    def is_attr_available(self, attr):
        try:
            hasattr(EmpDict, attr)
            return True
        except:
            return False

Here is the test:

>> emp = {'first_name' : 'Tom', 'last_name' : 'Jose'}

>> a = EmpDict(emp)
>> print(a.is_attr_available(a.first_name)) 
     True
>> print(a.is_attr_available(a.age))
     print(a.is_attr_available(a.age))
     AttributeError: 'EmpDict' object has no attribute 'age'

I expected False for the last statement, instead I get an AttributeError even though I also captured the exception in is_attribute_available method.

Any leads on what I am doing wrong here?

Upvotes: 3

Views: 2562

Answers (3)

U13-Forward
U13-Forward

Reputation: 71610

Agree with @blhsing, but I changed your code around a little bit,(there are some little things that can be better) one thing is that the second argument of hasattr should be a string not a attribute,

Example:

class EmpDict:
    def __init__(self, data):
        self.data = data
        try:
            self.first_name = data['first_name']
            self.age = data['age']
            self.last_name  = data['last_month']
        except:
            ()
    def is_attr_available(self, attr):
        return hasattr(self,attr)

emp = {'first_name' : 'Tom', 'last_name' : 'Jose'}
a = EmpDict(emp)
print(a.is_attr_available('age')) 

Output:

False

Also:

You don't need an try-except for hasattr (otherwise why is it called hasattr)

From the documentation:

hasattr(object, name)

The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.)

Here is a much better code for it:

class EmpDict:
    def __init__(self, data):
        self.data = data
        self.first_name = data.get('first_name')
        self.age = data.get('age')
        self.last_name  = data.get('last_month')
       
    def is_attr_available(self, attr):
        return hasattr(self, attr) and getattr(self,attr)!=None
        

emp = {'first_name' : 'Tom', 'last_name' : 'Jose'}
a = EmpDict(emp)
print(a.is_attr_available('age')) 

Upvotes: 1

abarnert
abarnert

Reputation: 366103

That's not how you use hasattr.

First, you use hasattr when you have the attribute name as a string value:

attrname = 'age'
hasattr(a, attrname)

You can't pass it a.age—that's already trying to look up a.age, and then pass the result of that as the attribute name. That will be false if there is an age (because you don't have an attribute named 23), and it won't even get to hasattr if there isn't one.


But there are two other problems with your code.

First, hasattr returns True if the attribute is there, False if it isn't. It only raises an exception if there's a typo in your code or a serious bug in your class (and you don't want an except: to catch those and just make the problem impossible to debug).

Second, EmpDict is the class. The class doesn't have any of these attributes, so that's always going to return false. You want to know if the instance, self, has them.

So:

def is_attr_available(self, attr):
    return hasattr(self, attr)

And then, you could change your code to call

print(a.is_attr_available('age'))

But really, why do you even want this function? Why not just:

  • try: the a.age?
  • … or provide a default value like None so the attribute always exists?

Upvotes: 3

blhsing
blhsing

Reputation: 107115

hasattr takes the attribute name as a string as the second argument, so you should pass to it the name of the attribute instead:

print(a.is_attr_available('age'))

Otherwise you would raise the AttributeError exception by trying to evaluate a.age.

Also, hasattr does not raise any exception, but simply returns True if the object has the attribute, so you should modify your is_attr_available function to:

def is_attr_available(self, attr):
    return hasattr(self, attr)

Upvotes: 1

Related Questions