PYTHON: Nameerror: name is not defined

Asked

Viewed 298 times

-3

What’s wrong with this code so I can’t call the function pontosNaBorda?

def pontosNaBorda(v0, v1, v2):
    # v0, v1, v2 são coordenadas dos vértices de um triângulo
    return v0

def main():
    alienigenas = []
    n = int(input("Quantidade de alienigenas: "))
    for i in range(0,n):
        alienigenas.append(leAlienigena(i))
        
def leAlienigena(numero_alienigena):
    coordenadas = input("Alienigena %d: " %(numero_alienigena))
    
    # converte a string lida em uma lista de inteiros
    coordenadas = coordenadas.split()
    for i in range(0,6):
        coordenadas[ i ] = int( coordenadas[ i ] )
        
    # separa as três coordenadas dos vértices do alienígena
    v0 = [ coordenadas[0], coordenadas[1] ]
    v1 = [ coordenadas[2], coordenadas[3] ]
    v2 = [ coordenadas[4], coordenadas[5] ]

    return v0, v1, v2

if __name__ == '__main__':
    main()

funcao = int(input("Digite a funcao que deseja testar: "))

if funcao == int(1):
    pontosNaBorda(v0, v1, v2)

The error that gives:

Traceback (most recent call last):   File "C:/Users/*/Downloads/EP3
(Prazo_ 03_07_21)/ep03-rascunho.py", line 32, in <module>
    pontosNaBorda(v0, v1, v2) NameError: name 'v0' is not defined

But the v0 is not defined in the function leAlienigena?

1 answer

5

Although you commented on another answer that "worked", I would like to leave an alternative - in my opinion - better.

First, using global variables - especially the way it was done in your program - doesn’t sound good (spoiler: usually it is not, read here, here, here and here).

For example, if you read the data of 10 aliens: at the end of the loop, the variables v0, v1 and v2 shall have only the values of the tenth. That is, the function pontosNaBorda ends up having only these last values. All the others you read earlier will be on the list alienigenas, it’s true, only this list isn’t being used for anything, so actually the whole code is pretty messed up.

But before you fix the code, I think you better understand an important concept: the scope of a variable.

Within the function leAlienigena you created the variables v0, v1 and v2 and returned them, which is why he thought they would also be available outside the function. But not really, because variables created within a function are local to this function: they only "exist" in there, no one outside can access them. Ex:

def funcao():
    x = 1

# executa a função
funcao()
print(x) # NameError: name 'x' is not defined

See that after executing the function, the variable x is not accessible outside of it. After all, x was declared within funcao and only exists inside (the scope of this variable is the function, outside of it nobody can "see" the x).

Ah, but what if I return the x?

def funcao():
    x = 1
    return x # agora eu retorno o x

# Ainda sim dá erro
funcao()
print(x) # NameError: name 'x' is not defined

It’s still a mistake. After all, the return x is just saying "return the value of expression x". That is, whoever calls the function has to take this value and do something with it (assign it in a variable, or use it directly in another expression):

def funcao():
    x = 1
    return x

# executa a função
valor = funcao()
print(valor) # 1
print(x) # NameError: name 'x' is not defined

See what I did valor = funcao() (the variable valor receives the value returned by funcao). See that the function returns the value that x had at the time it was executed. This value (which in this case is 1) was returned and placed in the variable valor. But after the function has finished executing, the variable x "some" (because being local to the function, it only exists inside, and when the function finishes executing, all local variables cease to exist). This is an important distinction because what is returned is the value, not the variable (read here for more details). See x continues not existing outside the function, and any attempt to access it will give error.

That’s why v0, v1 and v2 are not available outside the function leAlienigenas, and trying to pass them on to pontosNaBorda, gave the NameError.

In fact, the same goes for the list alienigenas, that exists only in the function main. After this function ends, you don’t use this list for anything else (not even return), so it ceases to exist. That is, you read a lot of data and then they disappear (and using global variables, you only have the last value typed, losing all the others that were stored in the list). So I thought it was strange that it "worked", I would review everything before being sure (it may be that the code is not complete and "makes sense", but only with what is in the question, it was very weird).


Fixing the code

Therefore, a better alternative would be to use the return of the functions, assigning them in variables and/or passing these values to the other functions.

To start, the program reads the coordinates of a or more aliens, storing them in a list. But as already said, this list is not used for anything, so a suggestion would be to return it:

def main():
    n = int(input("Quantidade de alienigenas: "))
    alienigenas = []
    for i in range(n):
        alienigenas.append(leAlienigena(i))
    return alienigenas # retorne a lista de alienígenas

And the reading can be simplified (taking into account that it is not made validation of the data, as for example, if it was really typed 6 numbers):

def leAlienigena(numero_alienigena):
    # converte a string lida em uma lista de inteiros
    coordenadas = list(map(int, input(f"Alienigena {numero_alienigena}: ").split()))

    # separa as três coordenadas dos vértices do alienígena
    v0 = coordenadas[0:2]
    v1 = coordenadas[2:4]
    v2 = coordenadas[4:6]
    return v0, v1, v2

And when running the program, you get the list of aliens returned by main:

if __name__ == '__main__':
    # pega os valores retornados
    alienigenas = main()

But just one detail: this list contains one or more tuples, each tuple contains 3 lists containing the coordinates of an alien. And how pontosNaBorda receive these 3 coordinates separately, you would have to pass them once to each alien. Something like this:

for v0, v1, v2 in alienigenas: # para cada alienígena, pegar as coordenadas
    pontosNaBorda(v0, v1, v2)

Or, if you want a specific alien:

v0, v1, v2 = alienigenas[0] # pega as coordenadas do primeiro alienígena
pontosNaBorda(v0, v1, v2)

Although it wasn’t clear what to do (but if you read the data of several aliens and stored it in a list, it seems to me it makes sense to analyze the coordinates of all, but there it is with you: now that you have the list with everything that was typed, it becomes simpler to decide what to do).

I mean, the whole code would be:

def pontosNaBorda(v0, v1, v2):
    return v0

def main():
    n = int(input("Quantidade de alienigenas: "))
    alienigenas = []
    for i in range(n):
        alienigenas.append(leAlienigena(i))
    return alienigenas # retorne a lista de alienígenas

def leAlienigena(numero_alienigena):
    # converte a string lida em uma lista de inteiros
    coordenadas = list(map(int, input(f"Alienigena {numero_alienigena}: ").split()))

    # separa as três coordenadas dos vértices do alienígena
    v0 = coordenadas[0:2]
    v1 = coordenadas[2:4]
    v2 = coordenadas[4:6]
    return v0, v1, v2

if __name__ == '__main__':
    # pega os valores retornados
    alienigenas = main()
    print(alienigenas)
    funcao = int(input("Digite a funcao que deseja testar: "))
    if funcao == 1: # assim, os valores estarão disponíveis aqui
        v0, v1, v2 = alienigenas[0] # pega as coordenadas do primeiro alienígena
        pontosNaBorda(v0, v1, v2)

It is important to note that the variables v0, v1 and v2 that were created within the if nay are the same that are within the function leAlienigena. They happen to have the same name, but remember the scope: the ones inside the function are local and only exist inside. It would be the same as having this:

def funcao():
    x = 1
    return x

x = 2
funcao()
print(x) # 2

This code prints "2" as the x that is within the function is different from the x outside. One does not interfere with the other.

This distinction is important to organize the code and leave the function more "self-contained". Every call to leAlienigena, She’s dealing with the data of a single alien. Leaving the global variables causes the semantics to mix: there is no more data from the current alien, but rather "the data", a single instance of it. And when calling the function pontosNaBorda, She will receive only the data of the last read alien. But if that was the intention, then why read data from various aliens, if in the end only the latter will be used? (that’s why I said the code is strange, and even stranger than the use of global has "solved" the problem - may have solved the NameError, but I suspect the logic is still weird and probably wrong).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.