Domanda

La variabile __debug__ è utile in parte perché influenza tutti i moduli. Se desidero creare un'altra variabile che funzioni allo stesso modo, come la farei?

La variabile (siate originali e chiamiamola 'pippo') non deve essere veramente globale, nel senso che se cambio pippo in un modulo, viene aggiornato in altri. Starei bene se potessi impostare foo prima di importare altri moduli e quindi vedrebbero lo stesso valore per esso.

È stato utile?

Soluzione

Non approvo questa soluzione in alcun modo, forma o forma. Ma se aggiungi una variabile al modulo __builtin__ , sarà accessibile come se fosse un globale da qualsiasi altro modulo che include __builtin__ - che è tutto loro, per impostazione predefinita .

a.py contiene

print foo

b.py contiene

import __builtin__
__builtin__.foo = 1
import a

Il risultato è che " 1 " è stampato.

Modifica: il modulo __builtin__ è disponibile come simbolo locale __builtins__ - questo è il motivo della discrepanza tra due di queste risposte. Si noti inoltre che __builtin__ è stato rinominato in builtins in python3.

Altri suggerimenti

Se hai bisogno di una variabile cross-module globale, forse basterà una semplice variabile globale a livello di modulo.

a.py:

var = 1

b.py:

import a
print a.var
import c
print a.var

c.py:

import a
a.var = 2

Prova:

$ python b.py
# -> 1 2

Esempio del mondo reale: Django's global_settings.py (sebbene nelle impostazioni delle app Django vengano utilizzate importando oggetto django.conf.settings ).

Definisci un modulo (chiamalo " globalbaz ") e includi le variabili definite al suo interno. Tutti i moduli che utilizzano questo "pseudoglobal" dovrebbe importare il "globalbaz" modulo e fare riferimento ad esso utilizzando " globalbaz.var_name "

Funziona indipendentemente dalla posizione della modifica, puoi cambiare la variabile prima o dopo l'importazione. Il modulo importato utilizzerà l'ultimo valore. (L'ho provato in un esempio di giocattolo)

Per chiarimenti, globalbaz.py è proprio così:

var_name = "my_useful_string"

Credo che ci siano molte circostanze in cui ha senso e semplifica la programmazione per avere alcuni globi che sono noti attraverso diversi moduli (strettamente accoppiati). In questo spirito, vorrei approfondire un po 'l'idea di avere un modulo di globali che viene importato da quei moduli che devono fare riferimento a loro.

Quando esiste un solo modulo, lo chiamo " g " ;. In esso, assegno i valori predefiniti per ogni variabile che intendo trattare come globale. In ogni modulo che ne utilizza uno, non utilizzo "da g import var", poiché ciò comporta solo una variabile locale che viene inizializzata da g solo al momento dell'importazione. Faccio la maggior parte dei riferimenti nella forma g.var e la "quot. G." serve a ricordare costantemente che ho a che fare con una variabile potenzialmente accessibile ad altri moduli.

Se il valore di una tale variabile globale deve essere usato frequentemente in alcune funzioni di un modulo, allora quella funzione può fare una copia locale: var = g.var. Tuttavia, è importante rendersi conto che i compiti di var sono locali e che g.var globale non può essere aggiornato senza fare esplicito riferimento a g.var in un compito.

Nota che puoi anche avere più di tali moduli globali condivisi da diversi sottoinsiemi dei tuoi moduli per mantenere le cose un po 'più strettamente controllate. Il motivo per cui uso nomi brevi per i miei moduli globali è per evitare di ingombrare troppo il codice con le loro occorrenze. Con solo una piccola esperienza, diventano abbastanza mnemonici con solo 1 o 2 personaggi.

È ancora possibile assegnare un compito, per esempio, a g.x quando x non era già definito in g, e un modulo diverso può quindi accedere a g.x. Tuttavia, anche se l'interprete lo consente, questo approccio non è così trasparente e lo evito. Esiste ancora la possibilità di creare accidentalmente una nuova variabile in g come risultato di un refuso nel nome della variabile per un compito. A volte un esame di dir (g) è utile per scoprire eventuali nomi a sorpresa che potrebbero essere sorti da tale incidente.

Puoi passare i globi di un modulo a un altro:

Nel modulo A:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

Nel modulo B:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3

Le variabili globali sono generalmente una cattiva idea, ma puoi farlo assegnando a __builtins__ :

__builtins__.foo = 'something'
print foo

Inoltre, i moduli stessi sono variabili a cui è possibile accedere da qualsiasi modulo. Quindi, se si definisce un modulo chiamato my_globals.py :

# my_globals.py
foo = 'something'

Quindi puoi usarlo anche ovunque:

import my_globals
print my_globals.foo

L'uso dei moduli piuttosto che la modifica di __builtins__ è generalmente un modo più pulito di creare globi di questo tipo.

Puoi già farlo con variabili a livello di modulo. I moduli sono uguali, indipendentemente dal modulo da cui vengono importati. Quindi puoi rendere la variabile una variabile a livello di modulo in qualunque modulo abbia senso inserirla e accedervi o assegnarla ad altri moduli. Sarebbe meglio chiamare una funzione per impostare il valore della variabile o renderla una proprietà di qualche oggetto singleton. In questo modo se alla fine devi eseguire del codice quando la variabile viene modificata, puoi farlo senza interrompere l'interfaccia esterna del modulo.

Di solito non è un ottimo modo per fare le cose & # 8212; l'uso dei globi raramente è & # 8212; ma penso che questo sia il modo più pulito per farlo.

Volevo pubblicare una risposta in cui si verifica un caso in cui la variabile non verrà trovata.

Le importazioni cicliche possono interrompere il comportamento del modulo.

Ad esempio:

first.py

import second
var = 1

second.py

import first
print(first.var)  # will throw an error because the order of execution happens before var gets declared.

main.py

import first

Su questo esempio dovrebbe essere ovvio, ma in una base di codice di grandi dimensioni, questo può essere davvero confuso.

Sembra modificare lo spazio dei nomi __builtin__ . Per farlo:

import __builtin__
__builtin__.foo = 'some-value'

Non utilizzare __builtins__ direttamente (notare gli extra " s ") - apparentemente questo può essere un dizionario o un modulo. Grazie a ??O????? per averlo sottolineato, ne è possibile trovare di più qui .

Ora foo è disponibile per l'uso ovunque.

Non consiglio di farlo in generale, ma l'uso di questo dipende dal programmatore.

L'assegnazione deve essere fatta come sopra, basta impostare foo = 'some-other-value' per impostarlo solo nello spazio dei nomi corrente.

Lo uso per un paio di funzioni primitive integrate che sentivo davvero mancanti. Un esempio è una funzione di ricerca che ha la stessa semantica di utilizzo di filtro, mappa, riduzione.

def builtin_find(f, x, d=None):
    for i in x:
        if f(i):
            return i
    return d

import __builtin__
__builtin__.find = builtin_find

Una volta eseguito (ad esempio importando vicino al punto di ingresso) tutti i moduli possono usare find () come se, ovviamente, fosse stato incorporato.

find(lambda i: i < 0, [1, 3, 0, -5, -10])  # Yields -5, the first negative.

Nota: puoi farlo, ovviamente, con il filtro e un'altra linea per testare la lunghezza zero o con una riduzione in una sorta di linea strana, ma ho sempre pensato che fosse strana.

Potrei ottenere variabili modificabili tra i moduli (o mutabili ) usando un dizionario:

# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60

# in myapp.mod1
from myapp import Timeouts

def wait_app_up(project_name, port):
    # wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
    # ...

# in myapp.test.test_mod1
from myapp import Timeouts

def test_wait_app_up_fail(self):
    timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
    Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
    with self.assertRaises(hlp.TimeoutException) as cm:
        wait_app_up(PROJECT_NAME, PROJECT_PORT)
    self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
    Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak

Quando si avvia test_wait_app_up_fail , la durata effettiva del timeout è di 3 secondi.

Mi chiedevo se sarebbe possibile evitare alcuni degli svantaggi dell'utilizzo delle variabili globali (vedi ad esempio http: //wiki.c2.com/?GlobalVariablesAreBad ) utilizzando uno spazio dei nomi di classe anziché uno spazio dei nomi globale / modulo per passare i valori delle variabili. Il codice seguente indica che i due metodi sono sostanzialmente identici. Vi è un leggero vantaggio nell'uso degli spazi dei nomi delle classi, come spiegato di seguito.

I seguenti frammenti di codice mostrano anche che gli attributi o le variabili possono essere creati ed eliminati in modo dinamico sia negli spazi dei nomi globali / dei moduli sia negli spazi dei nomi delle classi.

wall.py

# Note no definition of global variables

class router:
    """ Empty class """

Chiamo questo modulo 'wall' poiché è usato per far rimbalzare le variabili. Agirà come uno spazio per definire temporaneamente variabili globali e attributi a livello di classe del "router" di classe vuoto.

source.py

import wall
def sourcefn():
    msg = 'Hello world!'
    wall.msg = msg
    wall.router.msg = msg

Questo modulo importa wall e definisce una singola funzione sourcefn che definisce un messaggio e lo emette con due diversi meccanismi, uno via globals e uno tramite la funzione router. Si noti che le variabili wall.msg e wall.router.message sono definite qui per la prima volta nei rispettivi spazi dei nomi.

dest.py

import wall
def destfn():

    if hasattr(wall, 'msg'):
        print 'global: ' + wall.msg
        del wall.msg
    else:
        print 'global: ' + 'no message'

    if hasattr(wall.router, 'msg'):
        print 'router: ' + wall.router.msg
        del wall.router.msg
    else:
        print 'router: ' + 'no message'

Questo modulo definisce una funzione destfn che utilizza i due diversi meccanismi per ricevere i messaggi emessi dall'origine. Permette la possibilità che la variabile 'msg' non esista. destfn cancella anche le variabili una volta che sono state visualizzate.

main.py

import source, dest

source.sourcefn()

dest.destfn() # variables deleted after this call
dest.destfn()

Questo modulo chiama in sequenza le funzioni precedentemente definite. Dopo la prima chiamata a dest.destfn le variabili wall.msg e wall.router.msg non esistono più.

L'output del programma è:

globale: ciao mondo!
router: Ciao mondo!
globale: nessun messaggio
router: nessun messaggio

I frammenti di codice sopra mostrano che i meccanismi delle variabili modulo / globale e classe / classe sono sostanzialmente identici.

Se si devono condividere molte variabili, l'inquinamento dello spazio dei nomi può essere gestito utilizzando diversi moduli di tipo wall, ad es. wall1, wall2 ecc. o definendo diverse classi di tipo router in un singolo file. Quest'ultimo è leggermente più ordinato, quindi forse rappresenta un vantaggio marginale per l'uso del meccanismo variabile di classe.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top