Esse código aqui da erro:
http://pastebin.com/uUTWG2wb
UnboundLocalError: local variable 'valor' referenced before assignment
Porém esses aqui não dão erro:
http://pastebin.com/GCr8s0Y2
http://pastebin.com/GFpqsLJa
Alguém saberia me explicar o porquê disso?
------------------------------------
Python-Brasil
http://www.python.org.br/wiki/AntesDePerguntar
Links do Yahoo! Grupos
<*> Para visitar o site do seu grupo na web, acesse:
http://br.groups.yahoo.com/group/python-brasil/
<*> Para sair deste grupo, envie um e-mail para:
python-brasi...@yahoogrupos.com.br
<*> O uso que você faz do Yahoo! Grupos está sujeito aos:
http://br.yahoo.com/info/utos.html
> Galera,
>
> Esse código aqui da erro:
> http://pastebin.com/uUTWG2wb
>
> UnboundLocalError: local variable 'valor' referenced before assignment
>
> Porém esses aqui não dão erro:
> http://pastebin.com/GCr8s0Y2
> http://pastebin.com/GFpqsLJa
>
>
> Alguém saberia me explicar o porquê disso?
>
>
> ------------------------------------
>
> Python-Brasil
> http://www.python.org.br/wiki/AntesDePerguntar
> Links do Yahoo! Grupos
>
>
>
Quando você cria uma variável ela fica associada ao bloco em que ela foi
criada, nesse seu exemplo, a variável valor fica no escopo do
método metodo_1. Quando você faz o "valor = valor+1", na verdade você está
criando uma nova variável, com escopo mais interno (no método metodo_2). Aí
que está o problema.
A mesma coisa acontece nesse exemplo: http://dpaste.com/473746/
O Python permite que você acesse uma variável não-local, mas você não pode
atribuir valor a ela num escopo mais interno.
--
Felipe Bernardo Zorzo
[As partes desta mensagem que não continham texto foram removidas]
--
Felipe Bandeira
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
Isso é um problema de escopo. 'valor' está no escopo de metodo_1, mas
no momento que você faz assignment da variavel 'valor' dentro de
'metodo_2', o compilador (para bytecode) faz o que a gente conhece
como shadowing: se há um assignment para uma variável dentro de um
certo escopo, o python faz todas as referenciais àquele nome serem
locais.
Em python 3.x você pode dar uma "dica" ao compilador para não se
comportar assim adicionando a keyword nonlocal [1]
[1] http://docs.python.org/py3k/reference/simple_stmts.html#the-nonlocal-statement
o que você deveria estar querendo fazer provavelmente era verificar se
conseguiria alterar a variável do "metodo_1", isso não deu certo, o motivo
está na criação dinâmica de variáveis e variáveis com o mesmo nome, por trás
das câmeras o que acontece é o seguinte:
tudo é um objeto, certo?!, um objeto é formado por um identificador e uma
instancia de uma classe,
o identificador é o "nome" que vc dá pra ele, esse nome é um ponteiro para
uma instancia de uma classe (lembre-se que por trás ainda tem rotinas
escritas em c, ou java que utilizam explicitamente ou implicitamente
ponteiros e mallocs), mais ou menos assim:
nome_obj -> endereco_obj_na_memoria
quando vc cria um objeto o que o interpretador faz é nada mais nada menos
que criar um identificador, (no caso com nome "valor") que aponta para nulo
nome_obj -> Null
quando você atribui algo para essa nova variável que criou, o que ele faz é
o seguinte:
1º criar um espaço na memória com o tipo criado
2º fazer o identificador apontar para esse espaço na memória
assim vc fica com algo do tipo:
nome_obj -> novo_espaco_criado_do_tipo_escolhido
só que no python essas coisas ficam escondidas por trás do interpretador e
suas rotinas em c, vamos seguir os passos para rodar seu método:
>>print metodo_1(1)()
# o que acontece dentro do idle: blz, chama aí pra mim o "metodo_1" e passa
para ele o parâmetro 1
# agora dentro do método_1: êpa, recebi uma chamada, humm, o parâmetro é 1
# ok, interpretador, cria aí pra mim um identificador que aponta pra null
chamado valor,
# tá agora, cria um espaço na memória do tipo inteiro e atribui o valor 1
# certo, pra fechar faz o identificador "valor" apontar pra esse valor na
memória que eu criei aí.
# \0 ok, qual o próximo passo... criar uma função metodo_2 blz, cria ela pra
mim...
# próximo passo retornar pro idle essa metodo_2,
# ok, chama aí então a metodo_2...
#dentro da metodo_2: opa recebi uma chamada
# tenho que criar um identificador apontando pra null chamado valor
# agora criar um espaço na memoria do tipo... um null+integer ...ixi...,
valor não aponta pra ninguém
# retorne erro variável não inicializada
def metodo_1(valor):
def metodo_2():
valor = valor+1
return valor
return metodo_2
print metodo_1(1)()
entendeu.
nos dois exemplos que vc enviou, os nomes não são os mesmos, por isso não
existe esse problema, ele não atribui o identificador a ninguém igual e tudo
fica certinho
dentro do "metodo_2" o que acontece é o seguinte:
# cria aí o identificador valor2 apontando para null
# cria um espaço na memória do tipo daonde aponta o identificador
"valor":int + 1:int = int
# agora valor2 aponte para esse local criado na memória
def metodo_1(valor):
def metodo_2():
valor2 = valor+1
return valor2
return metodo_2
print metodo_1(1)()
def metodo_1(valor):
def metodo_2():
valor = 1
return valor
return metodo_2
print metodo_1(1)()
Em 4 de março de 2011 18:30, Caio Romão <caio...@gmail.com> escreveu:
>
>
> 2011/3/4 Thomaz de Oliveira dos Reis <tho...@gmail.com>:
> <snip>
>
> >
> > Alguém saberia me explicar o porquê disso?
> >
>
> Isso é um problema de escopo. 'valor' está no escopo de metodo_1, mas
> no momento que você faz assignment da variavel 'valor' dentro de
> 'metodo_2', o compilador (para bytecode) faz o que a gente conhece
> como shadowing: se há um assignment para uma variável dentro de um
> certo escopo, o python faz todas as referenciais àquele nome serem
> locais.
>
> Em python 3.x você pode dar uma "dica" ao compilador para não se
> comportar assim adicionando a keyword nonlocal [1]
>
> [1]
> http://docs.python.org/py3k/reference/simple_stmts.html#the-nonlocal-statement
>
>
>
--
"The real voyage of discovery consists not in seeking new landscapes but in
having new eyes."
-Marcel Proust
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
ele "recria" o "valor" mas não dá erro por atribuir um inteiro logo de cara
def metodo_1(valor):
def metodo_2():
valor = 1
return valor
return metodo_2
é isso aí, espero ter ajudado,
abç.
valor = 1
valor = valor + 1
print valor
você obtem 2, logo ele primeiro faz o valor+1 pra depois atribuir a
valor o valor... não seria?
2011/3/4 Eric Lopes <contato.e...@gmail.com>:
> eu acho curioso, pq quando vc faz:
>
> valor = 1
> valor = valor + 1
> print valor
>
> você obtem 2, logo ele primeiro faz o valor+1 pra depois atribuir a
> valor o valor... não seria?
Não quando a soma está em um escopo mais interno (por isso ele lança um
UnboundLocalError).
--
Felipe Bernardo Zorzo
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
Python-Brasil
http://www.python.org.br/wiki/AntesDePerguntar
Links do Yahoo! Grupos
<*> Para visitar o site do seu grupo na web, acesse:
> eu acho curioso, pq quando vc faz:
>
> valor = 1
> valor = valor + 1
> print valor
>
> você obtem 2, logo ele primeiro faz o valor+1 pra depois atribuir a
> valor o valor... não seria?
Mas neste caso, a variavel valor já foi iniciada, no exemplo que vc
mostrou existem duas variaveis valor, pois elas são locais. Uma não
sabe da existencia da outra. Apesar deste material ser implementado em
C, acho interessante[1], pois o funcionamento das variaveis neste caso
é semelhante;
[1] - http://www.mtm.ufsc.br/~azeredo/cursoC/aulas/c760.html
--
Elias Granja
Campinas - SP
eu não saberia responder isso com certeza, por sorte o Elias e o Felipe
estão aí.
mas com certeza foi um estudo de caso interessante, eu cavuquei um pouquinho
mais e pelo que eu entendi, ele deve fazer uma verificação das variáveis
utilizadas na função antes de criar a função em si com as rotinas em c e
reserva o identificador delas antes de começar a fazer atribuições, eu fiz
três testes um pouco mais simples do que os seus, em vez de retornar o
endereço de funções eu trabalhei só em cima da variável "valor" e retornei
somente o tipo da variavel "valor":
#1 - vimos que o resultado é 1 3 1, ou seja, "valor" de metodo_1 não é
alterado, sobrescrito, etc
def metodo_1(valor):
print valor
def metodo_2():
valor = 3
return valor
print metodo_2()
return valor
print metodo_1(1)
#2 - nesse exemplo vê-se que metodo_2 tem acesso a "valor" pois metodo_1
está em um nível acima
def metodo_1(valor):
print valor
def metodo_2():
print valor
valor2 = 3
return valor
print metodo_2()
return valor
print metodo_1(1)
# 3 - aqui que ferra tudo, metodo_2 não pode alterar "valor" da camada
superior (bendito seja o encapsulamento)
# então ele entende que vai ter que criar essa variável dentro de metodo_2,
mas ao fazer isso reserva o
# identificador para essa variável local e ferra-se tudo, note que pelo
simples fato de ter uma atribuição a esse
# identificador, daí (acho) que ele reserva o nome para uso interno,
atribuindo null, como expliquei no e-mail
# anterior e finalmente o inocente "print valor" que havia funcionado no
exemplo 2 não funciona mais, pois
# agora "valor" não está apontando pra lugar nenhum
def metodo_1(valor):
print valor
def metodo_2():
print valor # erro: valor não inicializado
valor = 3
return valor
print metodo_2()
return valor
print metodo_1(1)
muito legal o estudo de caso que você levantou, eu passaria despercebido por
isso facilmente
abç
Em 4 de março de 2011 23:17, Elias de Oliveira
<con...@eliasgranja.com>escreveu:
>
>
> Em 4 de março de 2011 23:13, Thomaz de Oliveira dos Reis
> <tho...@gmail.com> escreveu:
>
>
> > eu acho curioso, pq quando vc faz:
> >
> > valor = 1
> > valor = valor + 1
> > print valor
> >
> > você obtem 2, logo ele primeiro faz o valor+1 pra depois atribuir a
> > valor o valor... não seria?
>
> Mas neste caso, a variavel valor já foi iniciada, no exemplo que vc
> mostrou existem duas variaveis valor, pois elas são locais. Uma não
> sabe da existencia da outra. Apesar deste material ser implementado em
> C, acho interessante[1], pois o funcionamento das variaveis neste caso
> é semelhante;
>
> [1] - http://www.mtm.ufsc.br/~azeredo/cursoC/aulas/c760.html
>
> --
> Elias Granja
> Campinas - SP
>
>
>
--
"The real voyage of discovery consists not in seeking new landscapes but in
having new eyes."
-Marcel Proust
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
Curioso que ele da erro na linha do print, mas o erro não acontece se
trocarmos na linha de baixo a atribuição.
É como se antes de executar o método o interpretador procurasse por
todas as atribuições de variáveis.
2011/3/5 Eric Lopes <contato.e...@gmail.com>:
'
De fato ele faz isso no contexto de funções: ele dá uma olhada adiante
e assume que qualquer variável que sofra uma atribuição é uma variável
local (exceto aquelas explicitamente declaradas como global (ou
nonlocal no Python 3)).
Que eu saiba, é a única exceção para a regra de que o Python só lê o
código-fonte uma vez, e de cima para baixo.
--
Luciano Ramalho
programador repentista || stand-up programmer
Twitter: @luciano
Eu gosto mais da analogia de que ele le o código uma vez, e depois
executa de cima pra baixo (até pq não é uma analogia é exatamente como
ele faz :D) Essa primeira leitura serve para várias coisas, não só
para decidir o escopo das variaveis como também para erros de encoding
no codigo fonte, otimizações, e algumas outras decisões
--
Leonardo Santagada
Legal. Podemos dizer então que ele lê o código-fonte uma vez, daí gera
o bytecode e executa o bytecode, confere?
Para quem se interessa por este tema de como o interpretador realmente
funciona, eu bolei um exercício legal que uso em minhas oficinas.
O exercício é o seguinte: leia o código-fonte [1], mas não o execute
no Python. Escreva num papel em que ordem os pontos indicados por ->
vão aparecer na saída do programa.
Dica: o primeiro ponto que aparece na saída é '-> 1', mas o segundo
não é '-> 2'.
[1] http://code.google.com/p/propython/source/browse/fundamentos/execucao_pergunta.py
--
Luciano Ramalho
programador repentista || stand-up programmer
Twitter: @luciano