George Gkasdrogkas George Gkasdrogkas - 29 days ago 9
Python Question

Exception handling inside class constructor in python

I'm solving a small exercise from a beginners python book. I have to create a class

Flower
with three instance variables of type
str
,
int
, and
float
, that respectively represent the name of the flower, its number of petals, and its price. I also have to include methods for setting the value of each type, and retrieving the value of each type. I understand that the user can input any type he likes in the instance variables. For example, he might pass the number of petals to
Flower
instance as
str
and not as
int
. To avoid those problems I included simple
try/except
blocks in my class methods. Below is a working example:

class Flower:
"""A flower."""

def __init__(self, name, petals, price):
"""Create a new flower instance.

name the name of the flower (e.g. 'Spanish Oyster')
petals the number of petals exists (e.g. 50)
price price of each flower (measured in euros)
"""
self._name = str(name)
self._petals = petals
self._price = price

def set_name(self, name):
self._name = str(name)

def get_name(self):
return self._name

def set_petals(self, petals):
try:
self._petals = int(petals, 10)
except ValueError:
print('set_petals(): could not parse "%s" to int().' % petals)

def get_petals(self):
return self._petals

def set_price(self, price):
try:
self._price = float(price)
except ValueError:
print('set_price(): You should parse "%s" to float().' % price)

def get_price(self):
return self._price


if __name__ == '__main__':
rose = Flower('Rose', 60, 1.3)

print('%s contains %d petals costs %.2f euros.' % \
(rose.get_name(), rose.get_petals(), rose.get_price()))

rose.set_petals('error')


"""Initialize a new Flower instance with false values."""
sunflower = Flower('Sunflower', 'error', 'another error')

print('%s contains %d petals costs %.2f euros.' % \
(sunflower.get_name(), sunflower.get_petals(), \
sunflower.get_price()))


Explanation



Let's consider that a user initialize a new
Flower
instance:

rose = Flower('Rose', 60, 1.3)


Then he wants to update the number of petals, so he calls
set_petals()
method:

rose.set_petals('error')


My exception handling block catch this and prints:

set_petals(): could not parse "error" to int().


The same logic applies in
set_price()
method.

Now consider that he pass those false values to the constructor.

sunflower = Flower('Sunflower', 'error', 'another error')


In the constructor, as you see in my code, I don't check for type errors, so when I'm going to print the values from
sunflower
instance this is what I get in the output when I execute the second
print
:

TypeError: %d format: a number is required, not str


Problem



What I try to accomplish is to enter these type checks in the constructor as well. However, I'm new to python and do not know what is the best way to do it to keep the appropriate level of abstraction and not violate the DRY principle. One thought was to write
try/except
blocks in the constructor, but this would overwhelm my code. Another idea was to separate the error handling in different functions. How do I handle those type checks properly?

Answer Source

Simply do this:

   def __init__(self, name, petals, price):
        """Create a new flower instance.

        name    the name of the flower (e.g. 'Spanish Oyster')
        petals  the number of petals exists (e.g. 50)
        price   price of each flower (measured in euros)
        """
        self._name = str(name)
        self.set_petals(petals)
        self.set_price(price)