Referencing Python Variables

I'm learning programming on my own and as much as I search online, I can't understand exactly why the following reference doesn't work as I imagine it would.

Let's say I created a function to ask a question:

def Pergunta(X, Y):  
    X = input(Y)

Then I call the method and add a greeting:

Pergunta(Resposta, 'Qual o seu nome?')
print('Sejam bem-vindos, {}'.format(Resposta))

Python then complains that the variable Resposta is not defined, so I imagine I need to reference the variable before and this it was my solution:

def Pergunta(X, Y):  
    X = input(Y)

Resposta = ''
Pergunta(Resposta, 'Qual o seu nome?')
print('Sejam bem-vindos, {}!'.format(Resposta))

Apparently this solves the problem, but when I test the program, the reference in which Resposta = '' is not superimposed by the function that should turn it into "Leandro", for example. Instead, the program only prints:

Sejam bem-vindos, !

Does anyone know how to explain to me what I'm doing wrong or why the function doesn't rewrite the reference or what should I do to make it work that way ?

One thing that confuses me: when I write this command inside Method format, for some reason the reference works, but I wanted this greeting to be method independent.

I appreciate your attention.

Author: JeanExtreme002, 2020-01-11

2 answers

First of all, you should know that the variable Resposta and the variable X in your function are different. First because the nomenclature is different, so if you want to change the variable Resposta, you should have within your function a variable with the same name. Example:

def Pergunta(Y):  
    Resposta = input(Y)

Note two things in this example above. The first thing is that I removed the X parameter from the method signature. Maybe you think that by passing Resposta to X you pass the reference, but that it doesn't work with primitive types in Python, in fact, what you do is pass only the value of the variable.

Passing the reference as an argument to a function only works on objects such as lists, tuples, and others. Example:

# O que é passado para o parâmetro não é um valor e sim um endereço de memória, 
# já que se é passado uma lista e não um tipo primitivo.

def limpa(lista):  
    lista.clear()

minhaLista = [1,2,3]
limpa(minhaLista)

The second thing we can notice when running this function is that even fixing the variable name problem, the result will still not be what we want or even an error will be generated, like what happened with you before.

def Pergunta(Y):  
    Resposta = input(Y)

Pergunta('Qual o seu nome?')
print('Sejam bem-vindos, {}!'.format(Resposta))

NameError: name 'response' is not defined

This is because the variable Resposta inside the function is in a totally different scope than the variable Resposta outside the function. So the error in the example above is generated because the variable Resposta only exists within the function.

To better understand on the subject of scope I recommend that you read the article on this site. But simply put, the scope of the variable within its function is the scope local and outside the function, its variable is in the scope global.

Resposta = ""  # Escopo global

def Pergunta(Y):  
    Resposta = input(Y)  # Escopo local

The scope variable global will not be changed because the scope local has no connection to it. But we can change the scope variable global inside the function using the global declaration. See below:

def Pergunta(Y): 

    # Declara que a variável não pertence 
    # ao escopo local, e sim ao escopo global. 
    global Resposta

    Resposta = input(Y)

There is also another statement called nonlocal that has the same purpose as the statement global, but it will get the outermost function scope variable. Example:

# Escopo global (fora de funções, classes, métodos e outros)

def obterIdade(): # Escopo da função 1 (dentro da função obterIdade)

    idade = 15

    def acrescentaIdade(): # Escopo da função 2 (dentro da função acrescentaIdade)

        # Utilizar a declaração global não funcionaria pois a variável
        # não está no escopo global, e sim no escopo local da função 1.
        nonlocal idade
        idade += 1

Other than that, you should also know about the return. This statement is used to return one or more values of a function. In this way it is not necessary to change directly in the function the variable global. Example:

def Pergunta(Y):  
    nome = input(Y)
    return nome

resposta = Pergunta('Qual o seu nome?') # Obtém o valor retornado da função
print('Sejam bem-vindos, {}!'.format(resposta))

Now that you've learned all about scopes, declaration global and nonlocal, you can fix and improve your code, like this:

# Dica: Tenha sempre a atenção de criar nomes 
# bem definidos para suas variáveis e funções ;)

def perguntar(texto):
    global resposta
    resposta = input(texto)

perguntar('Qual o seu nome?')
print('Sejam bem-vindos, {}!'.format(resposta))
 1
Author: JeanExtreme002, 2020-01-11 20:37:13

Important to remember that in python the string are immutable so if you pass an immutable type in a method it will not be passed its reference, therefore it will not be possible to change.

But if you do this with a changeable object, such as a list, for example. The reference pass will be made through the method and thus it will be possible to change the object. Using your example only by changing the variable type from string to list

Resposta = list()

def Pergunta(X, Y):
    X.append(input(Y))

Pergunta(Resposta, 'Qual o seu nome?')
print('Sejam bem-vindos, {}!'.format(Resposta[0]))

We have the following output:

Qual o seu nome? Thiago
Sejam bem-vindos, Thiago!
 0
Author: Tmilitino, 2020-01-11 22:22:55