Escopos e argumentos mutáveis e coringas
Escopo
Agora que já falamos sobre a anatomia de uma função, vamos falar sobre o escopo de uma função.
Um escopo é similar a um namespace, um espaço do código onde os nomes são definidos. O isolamento de escopo é importante para que não haja conflito de nomes entre os identificadores.
Por exemplo, se tivermos duas funções e dentro do bloco de código de ambas
funções atribuirmos uma variável nome
, o Python cria dentro de cada função um
escopo chamado local
e define esse valor apenas ali dentro.
def nome_da_funcao1():
nome = 'valor'
nome = nome.upper()
return nome
def nome_da_funcao2():
nome = 'outro valor'
nome = nome.title()
return nome
print(nome_da_funcao1())
# VALOR
print(nome_da_funcao2())
# Outro Valor
Repare que apesar de terem o mesmo nome, cada função tem a sua própria variável
nome
e este identificador existe apenas dentro da função. (nome
não faz
parte do global frame
)
Em um programa Python existem os seguintes escopos:
Vamos ver como isso ficaria no código abaixo:
nome = 'valor'
def nome_da_funcao1():
nome = 'outro valor'
nome = nome.upper()
return nome
def nome_da_funcao2():
nome = 'outro valor'
nome = nome.title()
return nome
print(nome_da_funcao1())
# VALOR
print(nome_da_funcao2())
# Outro Valor
print(nome)
# valor
E ao criar uma variável nome = "valor"
no escopo principal, ou seja, o escopo
global, ela não conflita com as variáveis existentes dentro das funções.
O nome
do global frame
não é o mesmo do nome
da funcao1
que não é o
mesmo nome
da funcao2
.
Para verificar todas as variáveis do escopo global, podemos usar a função
globals()
.
E dentro de uma função, para verificar todas as variáveis do escopo local,
podemos usar a função locals()
.
Posso acessar uma variável global dentro da função?
Python decide qual é o escopo de uma variável quando a mesma é definida, no
momento da atribuição, portanto, ao criar nome = "valor"
dentro de uma função,
o Python determina que nome
pertence ao escopo local e não permite acessar a
variável nome
do escopo global.
nome = 'valor' # variável global
def funcao1():
nome = 'outro valor' # variável local
# alteração ocorre apenas no escopo local
nome = nome.upper()
return nome # o valor de retorno é o da variável local
print(funcao1()) # O valor de retorno é acessado
# OUTRO VALOR
print(nome) # Continua com o valor da variável global
# valor
Mas se por acaso quisermos acessar a variável nome do escopo global, podemos
usar a função globals() que é um dicionário que contém todas as variáveis do
escopo global.
nome = 'valor' # variável global
def funcao1():
nome = 'outro valor' # variável local
nome = nome + globals()['nome'] # acesso a variável global
return nome # o valor de retorno é o da variável local
print(funcao1()) # O valor de retorno é acessado
# outro valorvalor
print(nome) # Continua com o valor da variável global
# valor
E se a sua função não fizer atribuição a uma variável com o mesmo nome de uma variável global, então Python irá tentar acessar a variável global caso ela não exista no escopo local.
nome = "valor" # variável global
def funcao1():
return nome.upper() # acesso a variável global
print(funcao1())
# VALOR
Posso alterar o valor de uma variável global dentro de uma função?
Se o valor da variável global for imutável, então para alterar o apontamento da variável global precisaremos dizer ao Python que ao invés de estarmos fazendo uma nova atribuição local estamos substituindo o apontamento da variável global.
nome = "valor" # string imutável global
def muda_nome():
# explicitamante dizemos que a variavel é global
global nome
# reatribuição do apontamento da variável global
nome = "outro valor"
muda_nome()
print(nome)
# outro valor
Outro exemplo
contador = 0
def incrementa_contador():
global contador
contador += 1
incrementa_contador()
incrementa_contador()
print(contador)
# 2
Quando o valor da variável global for mutável, então podemos diretamente chamar seus métodos para alterar o valor dela.
numeros = [1, 2, 3]
def adiciona_numero(numero):
numeros.append(numero)
adiciona_numero(4)
adiciona_numero(5)
print(numeros)
# [1, 2, 3, 4, 5]
E neste caso não é preciso usar a keyword global
pois não faremos uma
reatribuição de apontamento, apenas chamada de método do protocolo do objeto.
Posso criar uma variável global dentro de uma função?
Sim, basta utilizar a palavra global
antes da variável que desejamos criar
globalmente.
def cria_nome():
global nome
nome = "valor"
print(nome)
# NameError: name 'nome' is not defined
cria_nome()
print(nome)
# valor