Search code examples
pythonnameerror

Why is the NameError from the set method in my Python class not working?


Okay here is the thing, this module is about creating “matrices”. No matter what dimension, the values all start filled with 0. I have a function named set, that exchanges one of the positions of the matrix for a specific number.

Example:

A = Matrix(3,3) 

print(A)
0 0 0 
0 0 0
0 0 0 
A.set(1,2,3)

print(A)
0 0 0
0 0 3
0 0 0

I need set to only accept numbers or floats, NO strings, so I raised a NameError, but it doesn't catch. It seems that for my code to work and to show the NameError I need to write with “”, because if not, it tells me is not defined.

I need these:

Example:

A.set(1,2,l) 

returns “Not a number or a float”

But instead im getting this

A.set(1,2,l)

returns “NameError: l is not defined”

What can i fix from my code so my NameError will be caught?

Here is my code:

class Matrix():
    
    def __init__(self,width,height):
        fill_value = 0
        self.height = height #columna
        self. width = width #fila
        self.rows = [[fill_value] * width for _ in range (height)]
        self.m = self.rows 
        
    def __str__(self):
        return "\n".join(" ".join(map(str, self.m))for self.m in self.m)
      
    def get(self, row_index, column_index):
        try:
            return self.m[row_index][column_index]
        except NameError:
            return "Its not a number"
        except IndexError:
            return "Not in matrix range" 

    def set(self, row_index,column_index,value):
        self.m[row_index][column_index] = value      

Pd. I’m trying doing it with get function (in this case with only int) and it also does not work.


Solution

  • The confusion is in how Python is interpreting the values you are passing into your function in the arguments.

    When you call the function like this:

    A.set(1,2,l) 
    

    You are passing 3 arguments:

    • 1, an integer number
    • 2, an integer number
    • The letter l, which is parsed as the name of a variable

    Python then checks it's various memory spaces (locals, etc.) looking for the variable l, but it cannot find it. Therefore, it is not even able to call your function and immediately returns a NameError, because one of the arguments to your set method had an error.

    If you want your argument to accept letters, then they must be a string type, which Python will parse when characters are enclosed in either single or double quotes:

    A.set(1, 2, 'l')
    

    Which would add the string with one character, 'l', into position (1, 2).

    Note that with your current code you will not generate an error here, because in your set method you don't have a try/catch block and aren't checking any types. If you want to prevent users from entering a string as a value, you would need to do some validation that it was the correct class, something like this:

    def set(self, row_index,column_index,value):
        if not isinstance(value, (int, float)):
            raise NameError(f"value (arg 3) must be an int or float, was a {type(value)}")
        else:
            self.m[row_index][column_index] = value
    

    And then I think you will want to wrap the self.m[row_index][column_index] = value into a try/catch to throw an error if the row or column inputs are not integers, or are out of range (the same you did in the get method).