Como chamo setattr () no módulo atual?


140

O que passo como o primeiro parâmetro " object" para a função setattr(object, name, value), para definir variáveis ​​no módulo atual?

Por exemplo:

setattr(object, "SOME_CONSTANT", 42);

dando o mesmo efeito que:

SOME_CONSTANT = 42

dentro do módulo que contém essas linhas (com o correto object).

Estou gerando vários valores no nível do módulo dinamicamente e, como não posso definir __getattr__no nível do módulo, esse é o meu fallback.

Respostas:


220
import sys

thismodule = sys.modules[__name__]

setattr(thismodule, name, value)

ou, sem usar setattr(que quebra a letra da pergunta, mas satisfaz os mesmos objetivos práticos ;-):

globals()[name] = value

Nota : no escopo do módulo, este último é equivalente a:

vars()[name] = value

que é um pouco mais conciso, mas não funciona de dentro de uma função ( vars()fornece as variáveis ​​do escopo em que é chamado: as variáveis ​​do módulo quando chamadas no escopo global e, em seguida, não há problema em usá-lo R / W, mas a função é variáveis ​​quando chamadas em uma função e, em seguida, devem ser tratadas como R / O - os documentos on-line do Python podem ser um pouco confusos sobre essa distinção específica).


9
Os documentos dão um aviso sobre a modificação de vars (). docs.python.org/library/functions.html#vars . Quando é bom fazer isso?
— Unutbu 29/05

2
@ ~ unutbu, eu realmente não diria que está "ok", mas funcionará quando você chamar vars()no escopo no nível do módulo, e não dentro de uma função.
— Mike Graham

4
vars()é equivalente a globals()no escopo do módulo (e, portanto, retorna um ditado verdadeiro e modificável), mas ao locals()escopo da função (e, portanto, retorna um pseudodict de nunca ser modificado). Eu uso vars()no escopo do módulo, pois economiza 3 caracteres, uma sílaba, vs seu sinônimo-em-que-scope globals();-)
— Alex Martelli

14
Sim, isso teria destruído a otimização mais importante que o compilador Python faz: as variáveis ​​locais de uma função não são mantidas em um ditado, elas estão em um vetor restrito de valores e cada acesso a variável local usa o índice nesse vetor, não uma pesquisa de nome. Para derrotar a otimização, forçando o ditado que você deseja existir, inicie a função com exec '': time uma função com alguns loops substanciais em cada sentido, e você verá a importância dessa otimização central para o desempenho do Python.
— Alex Martelli 29/05

3
@ msw, acho que você esqueceu de "praticidade supera pureza" ;-).
— Alex Martelli

6

Se você deve definir variáveis ​​de escopo do módulo de dentro do módulo, o que há de errado global?

# my_module.py

def define_module_scoped_variables():
    global a, b, c
    a, b, c = 'a', ['b'], 3

portanto:

>>> import my_module
>>> my_module.define_module_scoped_variables()
>>> a
NameError: name 'a' is not defined
>>> my_module.a
'a'
>>> my_module.b
['b']

1
Sim, eu sempre (onde "sempre" é definido como os "últimos meses que aprendi Python") achou essa global but not reallydeclaração intrigante. Suponho que possa ser uma relíquia histórica que antecede os espaços de nomes dos módulos.
— Msw

1
A pergunta original é perguntar como definir um atributo cujo nome é dado por uma string (a mesma coisa que eu estava procurando atualmente), portanto isso não ajudaria.
— Curt

6

No Python 3.7, você poderá usar __getattr__no nível do módulo ( resposta relacionada ).

Por PEP 562 :

def __getattr__(name):
    if name == "SOME_CONSTANT":
        return 42
    raise AttributeError(f"module {__name__} has no attribute {name}")

-1
  1. Você não faria. Você fariaglobals()["SOME_CONSTANT"] = 42
  2. Você não faria. Você armazenaria conteúdo gerado dinamicamente em outro lugar que não um módulo.

Sim, SOME_CONSTANTcalculado em tempo de execução não é exatamente constante. E se globals()não estiver disponível para você, você deverá acessar outro módulo para modificar seus atributos; isso deve fazer as pessoas se perguntarem.
— Msw

3
Constante e mutável são mutuamente exclusivos. Constante e gerado dinamicamente não são. Os valores que estou gerando são sempre os mesmos e determinados com base em outras "constantes", para economizar em aritmética e digitação da minha parte.
— Matt Joiner
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.