¿Cómo llamo a setattr () en el módulo actual?

140

¿Qué paso como primer parámetro " object" a la función setattr(object, name, value), para establecer variables en el módulo actual?

Por ejemplo:

setattr(object, "SOME_CONSTANT", 42);

dando el mismo efecto que:

SOME_CONSTANT = 42

dentro del módulo que contiene estas líneas (con el correcto object).

Genero varios valores a nivel de módulo de forma dinámica, y como no puedo definir __getattr__a nivel de módulo, esta es mi alternativa.

Matt Joiner
fuente

Respuestas:

220
import sys

thismodule = sys.modules[__name__]

setattr(thismodule, name, value)

o, sin usar setattr(que rompe la letra de la pregunta pero satisface los mismos propósitos prácticos ;-):

globals()[name] = value

Nota : en el alcance del módulo, este último es equivalente a:

vars()[name] = value

que es un poco más conciso, pero no funciona desde una función ( vars()proporciona las variables del alcance al que se llama: las variables del módulo cuando se llama al alcance global, y luego está bien usarlo R / W, pero la función es variables cuando se llama en una función, y luego debe tratarse como R / O: los documentos en línea de Python pueden ser un poco confusos sobre esta distinción específica).

Alex Martelli
fuente
9
Los documentos dan una advertencia sobre la modificación de vars (). docs.python.org/library/functions.html#vars . ¿Cuándo está bien hacer esto?
unutbu
2
@ ~ unutbu, realmente no diría que está bastante "bien", pero funcionará cuando llame vars()al alcance de nivel de módulo en lugar de dentro de una función.
Mike Graham
44
vars()es equivalente a globals()en el alcance del módulo (y, por lo tanto, devuelve un dict verdadero y modificable) pero a locals()en el alcance de la función (y, por lo tanto, devuelve un pseudodict que nunca se modificará). Lo uso vars()en el alcance del módulo, ya que guarda 3 caracteres, una sílaba, frente a su sinónimo en ese alcance globals();-)
Alex Martelli
14
Sí, habría destruido la optimización más importante que hace el compilador de Python: las variables locales de una función no se guardan en un dict, están en un vector de valores ajustado, y cada acceso a la variable local usa el índice en ese vector, no una búsqueda de nombre. Para vencer la optimización, forzando el dictado que desea que exista, inicie la función con exec '': cronometra una función con un par de bucles sustanciales en cada sentido, y verá la importancia de esta optimización central para el rendimiento de Python.
Alex Martelli
3
@msw, creo que olvidaste "la practicidad vence a la pureza" ;-).
Alex Martelli
6

Si debe establecer variables de ámbito del módulo desde dentro del módulo, ¿qué tiene de malo global?

# my_module.py

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

así:

>>> import my_module
>>> my_module.define_module_scoped_variables()
>>> a
NameError: name 'a' is not defined
>>> my_module.a
'a'
>>> my_module.b
['b']
msw
fuente
1
Sí, siempre (donde "siempre" se define como los "últimos meses que he estado aprendiendo Python") encontré esa global but not reallydeclaración desconcertante. Supongo que puede ser una reliquia histórica que antecede a los espacios de nombres del módulo.
msw
1
La pregunta original es cómo establecer un atributo cuyo nombre se le da por una cadena (lo mismo que estaba buscando actualmente), por lo que esto no ayudaría.
Curt
6

En Python 3.7, podrá usarlo __getattr__a nivel de módulo ( respuesta relacionada ).

Por PEP 562 :

def __getattr__(name):
    if name == "SOME_CONSTANT":
        return 42
    raise AttributeError(f"module {__name__} has no attribute {name}")
Trey Hunner
fuente
-1
  1. No lo harías Tu haríasglobals()["SOME_CONSTANT"] = 42
  2. No lo harías Almacenaría contenido generado dinámicamente en otro lugar que no sea un módulo.
Mike Graham
fuente
Sí, SOME_CONSTANTcalculado en tiempo de ejecución no es exactamente constante. Y si globals()no está disponible para usted, debe acceder a otro módulo para modificar sus atributos; eso hará que la gente se pregunte.
msw
3
Constante y mutable son mutuamente excluyentes. Constante y generado dinámicamente no lo son. Los valores que estoy generando son siempre los mismos, y se determinan en función de otras "constantes", para ahorrar en aritmética y escritura de mi parte.
Matt Joiner,