Pergunta

Eu corri através deste caso de UnboundLocalError recentemente, o que parece estranho:

import pprint

def main():
    if 'pprint' in globals(): print 'pprint is in globals()'
    pprint.pprint('Spam')
    from pprint import pprint
    pprint('Eggs')

if __name__ == '__main__': main()

Que produz:

pprint is in globals()
Traceback (most recent call last):
  File "weird.py", line 9, in <module>
    if __name__ == '__main__': main()
  File "weird.py", line 5, in main
    pprint.pprint('Spam')
UnboundLocalError: local variable 'pprint' referenced before assignment

pprint está claramente ligado no globals, e vai ser ligado no locals na seguinte declaração. Alguém pode oferecer uma explicação de por que ele não está feliz resolver pprint ao obrigatório em globals aqui?

Editar: Graças às boas respostas que eu possa esclarecer a minha pergunta com a terminologia relevante:

Em tempo de compilação do pprint identificador é marcado como local para o quadro. Será que o modelo de execução não têm nenhuma distinção , onde dentro do quadro do identificador local é obrigado? ele pode dizer, "referem-se ao global vinculativo até esta instrução bytecode, altura em que foi retomada a uma ligação local", ou faz o modelo de execução não são responsáveis ??por isso?

Foi útil?

Solução

Looks como Python vê a linha from pprint import pprint e marcas pprint como um nome local para main() antes executar qualquer código. Desde Python pensa pprint deveria ser uma variável local, referenciando-o com pprint.pprint() antes "atribuir" com a declaração from..import, ele lança esse erro.

Isso é tanto sentido como eu posso fazer isso.

A moral, é claro, é sempre colocar essas declarações import no topo do escopo.

Outras dicas

Onde está a surpresa? Qualquer variável global para um escopo que você atribuir novamente nesse âmbito é marcada local para que alcance pelo compilador.

Se as importações seriam tratados de forma diferente, que seria surpreendente imho.

Pode fazer um caso de não nomear módulos após símbolos usados ??no mesmo, ou vice-versa, no entanto.

Bem, isso foi o suficiente interessante para mim experimentar um pouco e eu ler http: / /docs.python.org/reference/executionmodel.html

Em seguida, fez alguns ajustes com o seu código aqui e ali, isso é o que eu poderia encontrar:

código:

import pprint

def two():
    from pprint import pprint
    print globals()['pprint']
    pprint('Eggs')
    print globals()['pprint']

def main():
    if 'pprint' in globals():
        print 'pprint is in globals()'
    global  pprint
    print globals()['pprint']
    pprint.pprint('Spam')
    from pprint import pprint
    print globals()['pprint']
    pprint('Eggs')

def three():
    print globals()['pprint']
    pprint.pprint('Spam')

if __name__ == '__main__':
    two()
    print('\n')
    three()
    print('\n')
    main()

saída:

<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Eggs'
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>

<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'

pprint is in globals()
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'
<function pprint at 0xb7d596f4>
'Eggs'

No two() método from pprint import pprint mas não se sobrepõe à pprint nome em globals, desde o global palavra-chave é não usado no âmbito da two().

Em three() método, pois não há declaração de nome pprint em âmbito local o padrão é o pprint nome global que é um módulo

Considerando que, main(), em primeiro lugar a palavra-chave global é usado para que todas as referências a pprint no âmbito da main() método irá se referir ao nome global pprint. Que como podemos ver é um módulo em primeiro lugar e é anulado na global namespace com um método de como fazemos o from pprint import pprint

Embora este não pode estar respondendo a pergunta como tal, mas, no entanto, a sua algum fato interessante que eu penso.

=====================

Editar Outra coisa interessante.

Se você tem uma palavra a dizer módulo:

mod1

from datetime import    datetime

def foo():
    print "bar"

e outro digamos método:

mod2

import  datetime
from mod1 import *

if __name__ == '__main__':
    print datetime.datetime.now()

que à primeira vista é aparentemente correta desde que você tenha importado o datetime módulo em mod2.

Agora, se você tentar executar mod2 como um script que irá lançar um erro:

Traceback (most recent call last):
  File "mod2.py", line 5, in <module>
    print datetime.datetime.now()
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'

porque o segundo from mod2 import * importação tem anulado o datetime nome no namespace, portanto, o primeiro import datetime não é mais válido.

Moral:. Assim, a ordem das importações, a natureza das importações (de x import *) ea consciência das importações dentro de módulos importados - importa

Esta questão foi respondida há várias semanas, mas eu acho que pode esclarecer as respostas um pouco. Primeiro alguns fatos.

1: Em Python,

import foo

é quase exatamente o mesmo que

foo = __import__("foo", globals(), locals(), [], -1)

2:. Ao executar código em uma função, se Python encontra uma variável que não tenha sido definido na função, no entanto, parece no escopo global

3: Python tem uma otimização ele usa para funções chamadas "locais". Quando Python tokenizes uma função, ele mantém o controle de todas as variáveis ??você atribui a. Ele atribui a cada uma dessas variáveis ??um número a partir de um número inteiro monotonicamente crescente local. Quando Python executa a função, ele cria um array com o maior número de aberturas, como existem variáveis ??locais, e atribui a cada slot de um valor especial que significa "não tenha sido atribuído a ainda", e é aí que os valores para as variáveis ??são armazenadas. Se você faz referência a um local que não tenha sido atribuído a ainda, Python vê esse valor especial e lança uma exceção UnboundLocalValue.

O palco já está definido. Seu "de pprint importação pprint" é realmente uma forma de atribuição. Então Python cria uma variável local chamada "pprint", que obstrui a variável global. Então, quando você se referir a "pprint.pprint" na função, você acertar o valor especial e Python lança a exceção. Se você não tem essa instrução de importação na função, Python usaria o primeiro e depois olhar-in-locals-olhar-em-globals resolução normal e encontrar o módulo pprint em globals.

Para disambiguate isso, você pode usar a palavra-chave "global". É claro que agora você já trabalhou passado o seu problema, e eu não sei se você realmente necessário "global" ou se alguma outra abordagem foi chamado para.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top