Reputation: 12515
I'm trying to see whether an instance of an attribute already exists for my object. As you can see below, I want to do something if my Dog
object has a certain attribute, via the do_something_if_has_aged
method. How can I check whether a certain attribute has already been declared? Usually you would check for existence with something like this, which returns False
:
obj = None
if obj:
print(True)
else:
print(False)
Here's my minimum reproducible example:
>>> class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def add_years(self, years):
self.age += years
self.has_aged = True
def do_something_if_has_aged(self):
if self.has_aged:
print("The dog has aged and is %d years closer to death" % self.years)
else:
print("The dog hasn't aged, apparently.")
>>> dog = Dog('Spot', 3)
>>> dog.age
3
>>> dog.do_something_if_has_aged()
Traceback (most recent call last):
File "<pyshell#193>", line 1, in <module>
dog.do_something_if_has_aged()
File "<pyshell#190>", line 9, in do_something_if_has_aged
if not self.has_aged:
AttributeError: 'Dog' object has no attribute 'has_aged'
>>> dog.add_years(1)
>>> dog.age
4
>>> dog.do_something_if_has_aged()
The dog hasn't aged, apparently.
Clearly the dog has aged, though.
I apologize if the title doesn't reflect what I'm trying to convey below; I'm new to OOP.
Upvotes: 1
Views: 143
Reputation: 1125058
Rather than test for the attribute, set a default value on the class; if an instance attribute is missing Python looks for a class attribute instead:
class Dog:
has_aged = False # default for all instances
def __init__(self, name, age):
self.name = name
self.age = age
def add_years(self, years):
self.age += years
self.has_aged = True # sets an instance attribute
def do_something_if_has_aged(self):
if self.has_aged:
print("The dog has aged and is %d years closer to death" % self.years)
else:
print("The dog hasn't aged, apparently.")
(note that I had to invert your test, if self.has_aged
is true you want to go into the first branch, not the other way around).
Or you can set a default value for the attribute in the __init__
:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
self.has_aged = False
def add_years(self, years):
self.age += years
self.has_aged = True
def do_something_if_has_aged(self):
if self.has_aged:
print("The dog has aged and is %d years closer to death" % self.years)
else:
print("The dog hasn't aged, apparently.")
You can also test if an attribute is present with the hasattr()
function:
def do_something_if_has_aged(self):
if hasattr(self 'has_aged') and self.has_aged:
print("The dog has aged and is %d years closer to death" % self.years)
else:
print("The dog hasn't aged, apparently.")
or by using the getattr()
function with a default value:
def do_something_if_has_aged(self):
if not getattr(self 'has_aged', False):
print("The dog has aged and is %d years closer to death" % self.years)
else:
print("The dog hasn't aged, apparently.")
However, testing dynamically for attributes should not be the first option you pick; having a class default is much cleaner.
Upvotes: 3
Reputation: 2575
To check if using hasattr
is perfectly fine, but in case you are looking for a quick fix for you code, you can do initialize the variable as false before hand:
class Dog:
has_aged = False
and also the fix your condition as i think it should be reversed:
def do_something_if_has_aged(self):
if self.has_aged: # instead of not self.has_aged
print("The dog has aged and is %d years closer to death" % self.years)
else:
print("The dog hasn't aged, apparently.")
Upvotes: 1
Reputation: 729
I would rewrite the __init__
method to include self.has_aged = False
to avoid having to do inspection:
class Dog(object):
def __init__(self, name, age):
self.name = name
self.age = age
self.has_aged = False # Starting value so it is guaranteed to be defined (unless explicitly deleted).
Now, the rest of your class should work as written. However, if you want to see if an attribute has been defined on an object, you can write this:
class Foo(object):
def set_bar(self):
self.bar = True # Define the attribute bar if it is not yet defined.
def is_bar_set(self):
return hasattr(self, 'bar')
Upvotes: 1
Reputation: 8254
It looks like you are looking for the hasattr
built-in function:
>>> class Dog(object):
... pass
...
>>> a = Dog()
>>> hasattr(a, 'age')
False
>>> a.age = 7
>>> hasattr(a, 'age')
True
In your case, you can modify as follows:
def do_something_if_has_aged(self):
if hasattr(self, 'has_aged'):
pass # do your logic
Upvotes: 4