Try statement with Boolean expressions inside a Class definition (including methods)

I’m trying to put the body of the definition of a class inside a try: statement. The constructor (init()) takes a list (or many values - it doesn’t matter). I want to execute the body of the class defining instance variables and methods only if certain conditions on the data types of the elements in the lists are met. For instance, I want the entry 0 (I shall use python position-based indexing) to be a string and the rest to be either float or int. Now, obviously I have check these condition after the init takes the list as a variable. If these are not met, not only I want the constructor to stop doing anything else, but also the methods above to not be run; effectively, if the conditions are not met, I would like the class to be equivalent to class “My_Class: <return + indent> pass:” (sorry if the written code jargon is wrong).
This is what I have so far and seem to work. But it’s messy. I appreciate Ideas.

code:

# WITH EXCPETION HANDLING
 
 class Patient:
    def __init__(self, lst):
        def checker(lst):
            for i in range(1, len(lst)):
                if type(lst[i]) in [int, float]:
                    continue
                else:
                    return False
            return True
        if (lst.__class__() == []) and (type(lst[0]) == str) and checker(lst) == True:
        
            self.name = lst[0]
            self.age = lst[1]
            self.sex = lst[2]
            self.bmi = lst[3]
            self.num_of_chidren = lst[4]
            self.smoker = lst[5]
        else:
            print('invalid data') #this won't work, I know. break? I have no clue
    
    try:
        def checker(lst):
            for i in range(1, len(lst)):
                if type(lst[i]) in [int, float]:
                    continue
                else:
                    return False
            return True
        if (lst.__class__() == []) and (type(lst[0]) == str) and checker(lst) == True:
        
            def estimated_insurance_cost(self):
                estimated_cost = 250*self.age -128*self.sex
                print("{Patient_Name}’s estimated insurance costs is {estimated_cost} dollars.".format(Patient_Name = self.name, estimated_cost = estimated_cost))

            def update_age(self, new_age):
                self.age = new_age
                print('{Patient_Name} is now {Patient_Age} years old.'.format(Patient_Name = self.name, Patient_Age = self.age))
                self.estimated_insurance_cost() 

            def update_num_children(self,new_num_children):
                self.num_of_children = new_num_children
                if self.num_of_children == 1:
                    print("{} has {} child.".format(self.name, self.num_of_children))
                else:
                    print("{} has {} children.".format(self.name, self.num_of_children))
                self.estimated_insurance_cost()

            def patient_profile(self):
                patient_information = {'Name':self.name, 'Age': self.age, 'Sex': self.sex, 'BMI': self.bmi, 'Children': self.num_of_children, 'Smoker': self.smoker}
                return patient_information
    except:
        def estimated_insurance_cost(self):
            print('obj has invalid data')
        def update_age(self, new_age):
            print('obj has invalid data')
        def update_num_children(self,new_num_children):
            print('obj has invalid data')
        def patient_profile(self):
            print('obj has invalid data')



### you may try this as follows
patient_data = ["John Doe", 25, 1, 22.2, 0, 0]
patient1 = Patient(patient_data)
patient1.estimated_insurance_cost()
fake_data = ["John Doe", 'abc', 1, 22.2, 0, 0]
patient1 = Patient(fake_data)
patient1.estimated_insurance_cost()
   

I appreciate, thanks!

you could just copy paste your code to the forum? Then apply format/markup like explained in step 3 of this topic:

[How-to] Create a topic that everyone will read

you can ignore the other steps, you have done those.

Written above. Good call, thanks!

I am very confused by your approach, here is what I would do:

make a method checker:

class Patient:
    def __init_(self, lst):
       # call checker

    def checker(lst):
       # do you checks

then within the init method, call the checker method. Depending on what checker returns, initialize the instance variable, or print an error message (or maybe even raise an exception)

Yes, apparently I could define it as a method outside the constructor and then call it when I need it. I think the key issue here though, is that - if the conditions are not met - I need to stop the code from executing the other methods. This is why all other methods need to be logically subordinate to the conditions being met. (Note the checker is just a function that I am using to checking that all the entries of the list but the first one are numerical).

If the other methods are not arranged in this way, then they are executed, independently of whether they are inside a try keyword followed by an exception raised, or not. I believe it’s because they are functions, so they will execute no matter what variables are passed it. But once you call these methods on a class object you get an error.

For this reason, I needed a way to create an error - when the conditions are not met - before the method definitions. Hence, the conditional statement and the definition (or I could also call it as you pointed out) before the methods are defined.

but then __init__ simple should throw an exception (when checker returns false).

Then you can do:

try:
     patient1 = Patient(patient_data)
     patient1.estimated_insurance_cost()
except TheException:
   print("not a valid patient")

where TheException is the exception you are actually throwing.

now if the constructor throws an exception, the other methods are not executed.

1 Like

Oh I see what you mean. Thanks, I’ll try that out.

Hi guys, I have been trying to do something similar to this but I am having some trouble in the init constructor.

First I have built a checker:

def cheker(x):
  for i in range(1,len(x)):
    if type(x[i]) != int and type(x[i]) != float:
      raise Exception("Not a number")

I test this within a try-except block and it works fine:

x = ["Jane", 21, 0, 1]

try:
  cheker(x)
except:
  print("Error: x must be a number")
else:
  print("All good")

Prints "All good"

But then when I move this to the class definition:

class NewPatients:
  def cheker(x):
    for i in range(1,len(x)):
      if type(x[i]) != int and type(x[i]) != float:
        raise Exception("Not a number")

  def __init__(self, patient_data_list):
    try:
      cheker(patient_data_list)
    except:
      print("Error: Age, sex, bmi, number of children and smoking status must be expressed in numbers.")
    else:
      self.name = patient_data_list[0]
      self.age = patient_data_list[1]
      self.sex = patient_data_list[2]
      self.bmi = patient_data_list[3]
      self.num_of_children = patient_data_list[4]
      self.smoker = patient_data_list[5]

patient2_data = ["Mary Jane", 21, 0, 20.2, 0, 1]
patient2 = NewPatients(patient2_data)

This prints the Error message… no matter what.
Can you help me spot my mistake?

I would not use Exception, this will catch all exceptions including NameError or SyntaxError. Making your code very difficult to debug

There is a TypeError, which sounds about right:

raise TypeError("Not a number")

then only catch the TypeError:

except TypeError:

otherwise you can make a custom exception

1 Like

Thank you very much.

This helped me to notice that I was not calling the checker function properly, now it works :smiley:

class NewPatients:
  def checker(x):
      for i in range(1,len(x)):
        if type(x[i]) != int and type(x[i]) != float:
          raise TypeError("Not a number") 

  def __init__(self, patient_data_list):
    try:
      NewPatients.checker(patient_data_list)
    except TypeError:
      print("Error: Age, sex, bmi, number of children and smoking status must be expressed in numbers.")
    else:
      self.name = patient_data_list[0]
      self.age = patient_data_list[1]
      self.sex = patient_data_list[2]
      self.bmi = patient_data_list[3]
      self.num_of_children = patient_data_list[4]
      self.smoker = patient_data_list[5]

patient2_data = ["Mary Jane", 21, 0, 20.2, 0, 1]
patient2 = NewPatients(patient2_data)

The most important thing here to understand is that exceptions are also classes, and Exception is the base class. All other exceptions (like NameError, TypeError) inherit from Exception class. Which why you rarely should catch Exception itself, given all the children it has