Come posso chiamare setattr () sul modulo corrente?


140

Cosa devo passare come primo parametro " object" alla funzione setattr(object, name, value)per impostare le variabili sul modulo corrente?

Per esempio:

setattr(object, "SOME_CONSTANT", 42);

dando lo stesso effetto di:

SOME_CONSTANT = 42

all'interno del modulo contenente queste righe (con il corretto object).

Sto generando diversi valori a livello di modulo in modo dinamico e, poiché non riesco a definire __getattr__a livello di modulo, questo è il mio fallback.

Risposte:


220
import sys

thismodule = sys.modules[__name__]

setattr(thismodule, name, value)

o, senza usare setattr(che rompe la lettera della domanda ma soddisfa gli stessi scopi pratici ;-):

globals()[name] = value

Nota : nell'ambito del modulo, quest'ultimo equivale a:

vars()[name] = value

che è un po 'più conciso, ma non funziona dall'interno di una funzione ( vars()fornisce le variabili dell'ambito in cui è chiamato: le variabili del modulo quando viene chiamato in ambito globale, e quindi è OK usarlo R / W, ma la funzione è variabili quando vengono chiamate in una funzione, e quindi devono essere trattate come R / O - i documenti online di Python possono essere un po 'confusi su questa distinzione specifica).


9
I documenti danno un avvertimento sulla modifica di vars (). docs.python.org/library/functions.html#vars . Quando va bene farlo?
unutbu,

2
@ ~ unutbu, non direi che è abbastanza "ok", ma funzionerà quando chiami vars()a livello di modulo piuttosto che all'interno di una funzione.
Mike Graham,

4
vars()è equivalente globals()all'ambito del modulo (e quindi restituisce un dict vero e modificabile) ma locals()all'ambito della funzione (e quindi restituisce uno pseudodict che non deve mai essere modificato). Uso l' vars()ambito del modulo in quanto salva 3 caratteri, una sillaba, rispetto al suo sinonimo-in-that-scope globals();-)
Alex Martelli,

14
Sì, avrebbe distrutto la singola più importante ottimizzazione del compilatore Python: le variabili locali di una funzione non sono tenute in un dict, sono in un vettore stretto di valori e ogni accesso alla variabile locale utilizza l'indice in quel vettore, non una ricerca per nome. Per sconfiggere l'ottimizzazione, forzando il dict che desideri esistere, avvia la funzione con exec '': time una funzione con un paio di loop sostanziali in ogni modo, e vedrai l'importanza di questa ottimizzazione di base per le prestazioni di Python.
Alex Martelli,

3
@msw, penso che tu abbia dimenticato "la praticità batte la purezza" ;-).
Alex Martelli,

6

Se è necessario impostare le variabili con ambito del modulo all'interno del modulo, cosa c'è che non va global?

# my_module.py

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

in tal modo:

>>> 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
Sì, ho sempre (dove "sempre" è definito come "gli ultimi mesi ho imparato Python") ho trovato tale global but not reallydichiarazione sconcertante. Suppongo che potrebbe essere una reliquia storica che precede gli spazi dei nomi dei moduli.
msw,

1
La domanda originale è chiedere come impostare un attributo il cui nome è dato da una stringa (la stessa cosa che stavo cercando attualmente), quindi questo non sarebbe d'aiuto.
Curt

6

In Python 3.7, sarai in grado di utilizzare __getattr__a livello di modulo ( risposta correlata ).

Per PEP 562 :

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

-1
  1. Non lo faresti. Lo farestiglobals()["SOME_CONSTANT"] = 42
  2. Non lo faresti. Conserveresti il ​​contenuto generato dinamicamente in un luogo diverso da un modulo.

Sì, SOME_CONSTANTcalcolato in fase di esecuzione non è esattamente costante. E se globals()non è disponibile per te, devi raggiungere un altro modulo per modificarne gli attributi; questo è destinato a far riflettere le persone.
msw,

3
Costante e mutevole si escludono a vicenda. Non sono costanti e generati dinamicamente. I valori che sto generando sono sempre gli stessi e determinati sulla base di ulteriori "costanti", per risparmiare sull'aritmetica e sulla digitazione da parte mia.
Matt Joiner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.