Pergunta

locals é construído em uma função que retorna um dicionário de valores locais. A documentação diz:

Atenção

O conteúdo deste dicionário deve não ser modificado; alterações podem não afetam os valores das variáveis ??locais usado pelo intérprete.

Infelizmente, exec tem o mesmo problema em Python 3.0. Existe alguma maneira redonda isso?

Caso de Uso

Considere o seguinte:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

depende lojas as cordas fornecidas em seus argumentos em uma lista test.dependences. Essas seqüências são chaves em uma d dicionário. Eu gostaria de ser capaz de capaz de escrever put_into_locals para que pudéssemos puxar os valores para fora do d e colocá-los nos locais. Isso é possível?

Foi útil?

Solução

Eu apenas testada exec e funciona em Python 2.6.2

>>> def test():
...     exec "a = 5"
...     print a
...
>>> test()
5

Se você estiver usando Python 3.x, ele não funciona mais, porque os habitantes locais são otimizados como uma matriz em tempo de execução, em vez de usar um dicionário.

Quando Python detecta a "declaração exec", ele irá forçar Python para mudar o armazenamento local de matriz para dicionário. No entanto uma vez que "exec" é uma função em Python 3.x, o compilador não pode fazer esta distinção desde que o usuário poderia ter feito algo como "exec = 123".

http://bugs.python.org/issue4831

Para modificar os locais de uma função em a mosca não é possível sem várias conseqüências: normalmente, locais de funções não são armazenados em um dicionário, mas uma matriz, cuja índices são determinados em tempo de compilação a partir dos locais conhecidos. Isso colide pelo menos com novos moradores adicionadas por exec. A declaração exec velho contornado isso, porque o compilador sabia que se um executivo sem globais / locals args ocorreu numa função, que namespace seria "Unoptimized", isto é, não utilizando o moradores matriz. Desde exec () é agora um função normal, o compilador não sabe o que "exec" pode ser ligado a, e portanto, não pode tratar é especialmente.

Outras dicas

As variáveis ??locais são modificados por instruções de atribuição.

Se você tiver chaves de dicionário que são cordas, por favor, não também torná-los variáveis ??locais -. Apenas usá-los como chaves de dicionário

Se você absolutamente deve ter variáveis ??locais fazer isso.

def aFunction( a, b, c, d, e, f ):
    # use a, b, c, d, e and f as local variables

aFunction( **someDictWithKeys_a_b_c_d_e_f )

Isso irá preencher algumas variáveis ??locais de seu dicionário sem fazer nada mágico.

Isto não é possível. Acho que isso é para permitir otimizações de desempenho mais tarde. Python bytecode referências locals pelo índice, e não pelo nome; se os moradores () foi obrigado a ser escrito, poderia evitar intérpretes de implementar algumas otimizações, ou torná-los mais difícil.

Estou bastante certo você não vai encontrar qualquer API núcleo que garantias você pode editar os habitantes locais como este, porque se isso API poderia fazê-lo, os moradores () não tem essa restrição também.

Não se esqueça que todos os moradores devem existir em tempo de compilação; se você faz referência um nome que não está vinculado a um local em tempo de compilação, o compilador assume que é um global. Você não pode "criar" moradores após a compilação.

Veja este questão para uma solução possível, mas é um corte sério e você realmente não quer fazer isso.

Note que há um problema básico com o seu código de exemplo:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

"test.dependencies" não está se referindo a "f.dependencies" onde F é a função atual; ele está fazendo referência ao valor global de real "teste". Isso significa que se você usar mais de um decorador:

@memoize
@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

isso vai deixar de trabalho, uma vez que "teste" é memoize está função embrulhado, não depende de. Python realmente precisa de uma forma para se referir a "a função actualmente em execução" (e classe).

Gostaria de armazená-lo em uma variável:

refs    = locals()
def set_pets():
    global refs
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
    for i in range(len(animals)):
        refs['pet_0%s' % i] = animals[i]

set_pets()
refs['pet_05']='bird'
print(pet_00, pet_02, pet_04, pet_01, pet_03, pet_05 )
>> dog fish monkey cat fox bird

E se você quiser testar o seu dict antes de colocá-lo em locals ():

def set_pets():
    global refs
    sandbox = {}
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
    for i in range(len(animals)):
        sandbox['pet_0%s' % i] = animals[i]
    # Test sandboxed dict here
    refs.update( sandbox )

Python 3.6.1 no MacOS Sierra

Eu não tenho certeza se ele está sujeito às mesmas restrições, mas você pode obter uma referência direta ao quadro atual (e, de lá, as variáveis ??locais dicionário) através do módulo inspecionar:

>>> import inspect
>>> inspect.currentframe().f_locals['foo'] = 'bar'
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect']
>>> foo
'bar'
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top