2008-09-26 11 views
106

La variable __debug__ es útil en parte porque afecta a todos los módulos. Si quiero crear otra variable que funcione de la misma manera, ¿cómo lo haría?Python: ¿Cómo hacer una variable de módulo cruzado?

La variable (seamos originales y llámala 'foo') no tiene que ser realmente global, en el sentido de que si cambio foo en un módulo, se actualiza en otros. Estaría bien si pudiera establecer foo antes de importar otros módulos y luego verían el mismo valor para él.

Respuesta

94

No apruebo esta solución de ninguna manera o forma. Pero si agrega una variable al módulo __builtin__, se podrá acceder como si fuera un elemento global de cualquier otro módulo que incluya __builtin__, que son todos ellos, de forma predeterminada.

a.py contiene

print foo 

b.py contiene

import __builtin__ 
__builtin__.foo = 1 
import a 

El resultado es que se imprime "1".

Editar: El módulo __builtin__ está disponible como el símbolo local de __builtins__ - que es la razón de la discrepancia entre dos de estas respuestas. También tenga en cuenta que __builtin__ ha cambiado de nombre a builtins en python3.

+2

¿Alguna razón, que no te gusta esta situación? –

+26

Por un lado, rompe las expectativas de las personas cuando están leyendo el código. "¿Qué es este símbolo 'foo' que se usa aquí? ¿Por qué no puedo ver dónde está definido?" –

+8

También es susceptible de causar estragos si una versión futura de Python comienza a usar el nombre que usted eligió como un builtin real. – intuited

2

Esto suena como la modificación del espacio de nombre __builtin__. Para hacerlo:

import __builtin__ 
__builtin__.foo = 'some-value' 

No utilice el __builtins__ directamente (note la "s" adicionales) - al parecer, esto puede ser un diccionario o un módulo. Gracias a ΤΖΩΤΖΙΟΥ por señalar esto, se puede encontrar más here.

Ahora foo está disponible para usar en todas partes.

No recomiendo hacer esto en general, pero el uso de esto depende del programador.

La asignación debe realizarse como se indica anteriormente, solo estableciendo foo = 'some-other-value' solo se configurará en el espacio de nombre actual.

+1

Recuerdo (de comp.lang.python) que se debe evitar el uso directo de __builtins__; en cambio, importe __builtin__ y úselo, como lo sugirió Curt Hagenlocher. – tzot

20

Defina un módulo (llámelo "globalbaz") y tenga las variables definidas dentro de él. Todos los módulos que usan este "pseudoglobal" deben importar el módulo "globalbaz", y se refieren a él usando "globalbaz.var_name"

Esto funciona independientemente del lugar del cambio, puede cambiar la variable antes o después de la importación . El módulo importado usará el último valor. (He probado esto en un ejemplo de juguete)

Para mayor claridad, globalbaz.py se parece a esto:

var_name = "my_useful_string" 
131

Si necesita una variable global del módulo transversal tal vez será suficiente una simple variable de nivel de módulo global .

a.py:

var = 1 

b.PY:

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

c.py:

import a 
a.var = 2 

prueba:

$ python b.py 
# -> 1 2 

mundo real ejemplo: Django's global_settings.py (aunque en Django apps ajustes se utilizan importando el objeto django.conf.settings)

+2

Mejor porque evita posibles conflictos de espacio de nombres – bgw

+0

¿Qué pasa si el módulo que está importando, en este caso 'a.py', contiene' main() '? ¿Importa? – sedeh

+4

@sedeh: no. Si a.py también se ejecuta como una secuencia de comandos, utilice 'if __name __ ==" __ main __ "' guard en ella para evitar la ejecución de código inesperado en la importación. – jfs

7

Las variables globales son por lo general una mala idea, pero se puede hacer esto mediante la asignación a __builtins__:

__builtins__.foo = 'something' 
print foo 

Además, los módulos mismos son variables que se puede acceder desde cualquier módulo. Así que si se define un módulo llamado my_globals.py:

# my_globals.py 
foo = 'something' 

entonces usted puede utilizar que desde cualquier lugar, así:

import my_globals 
print my_globals.foo 

el uso de módulos en lugar de modificar __builtins__ es generalmente una forma más limpia de hacer globales de este tipo .

+2

'__builtins__' es una peculiaridad de CPython, realmente no debería usarlo - mejor use' __builtin__' (o 'builtins' en Python3) como [la respuesta aceptada] (http://stackoverflow.com/a/142566/321973) muestra –

9

Puede pasar las variables globales de un módulo a onother:

En el Módulo A:

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

En el Módulo B:

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

¡práctico para probar! –

5

ya se puede hacer esto con módulo de nivel variables. Los módulos son los mismos sin importar de qué módulo se importen. De modo que puede hacer que la variable sea una variable a nivel de módulo en cualquier módulo que tenga sentido ponerlo, y acceder a él o asignarlo desde otros módulos. Sería mejor llamar a una función para establecer el valor de la variable, o para que sea una propiedad de algún objeto singleton. De esta forma, si necesita ejecutar algún código cuando la variable ha cambiado, puede hacerlo sin romper la interfaz externa de su módulo.

No suele ser una gran manera de hacer cosas, usar globals rara vez lo es, pero creo que esta es la forma más limpia de hacerlo.

1

Utilizo esto para un par de funciones primitivas integradas que realmente sentía que faltaban. Un ejemplo es una función de búsqueda que tiene la misma semántica de uso que filter, map, reduce.

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 vez que esto está dirigido (por ejemplo, mediante la importación de cerca de su punto de entrada) todos los módulos se pueden utilizar find(), como si, obviamente, que fue construido en

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

. Nota: Puede hacer esto, por supuesto, con filtro y otra línea para probar la longitud cero, o con reducir en un tipo de línea extraña, pero siempre sentí que era extraño.

20

Creo que hay muchas circunstancias en las que tiene sentido y simplifica la programación para tener algunos valores globales conocidos en varios módulos (estrechamente acoplados).Con este espíritu, me gustaría explayarme un poco sobre la idea de tener un módulo de globales que es importado por aquellos módulos que necesitan referenciarlos.

Cuando solo hay un módulo de este tipo, lo llamo "g". En él, asigno valores por defecto para cada variable que pretendo tratar como global. En cada módulo que utiliza cualquiera de ellos, no utilizo "from g import var", ya que esto solo da como resultado una variable local que se inicializa desde g solo en el momento de la importación. Hago la mayoría de las referencias en la forma g.var y la "g". sirve como un recordatorio constante de que estoy tratando con una variable potencialmente accesible para otros módulos.

Si el valor de dicha variable global se va a utilizar con frecuencia en alguna función en un módulo, entonces esa función puede hacer una copia local: var = g.var. Sin embargo, es importante darse cuenta de que las asignaciones a var son locales, y global g.var no se puede actualizar sin hacer referencia explícitamente a g.var en una asignación.

Tenga en cuenta que también puede tener varios de estos módulos globales compartidos por diferentes subconjuntos de sus módulos para mantener las cosas un poco más controladas. La razón por la que uso nombres cortos para mis módulos globales es para evitar saturar el código demasiado con las ocurrencias de ellos. Con solo un poco de experiencia, se vuelven mnemotécnicos con solo 1 o 2 caracteres.

Todavía es posible hacer una asignación, por ejemplo, g.x cuando x no estaba ya definido en g, y un módulo diferente puede acceder a g.x. Sin embargo, aunque el intérprete lo permita, este enfoque no es tan transparente, y lo evito. Todavía existe la posibilidad de crear accidentalmente una nueva variable en g como resultado de un error tipográfico en el nombre de la variable para una tarea. Algunas veces, un examen de dir (g) es útil para descubrir cualquier nombre sorpresa que pueda haber surgido de tal accidente.

+5

Esta interesante observación resolvió mi problema: 'No uso' de g import var ', ya que esto solo da como resultado una variable local que se inicializa desde g solo en el momento de la importación.' Parece razonable suponer que "from..import" es lo mismo que "import", pero esto no es cierto. –

0

que podía lograr ( mutables o ) las variables modificables-módulo cruz mediante el uso de un diccionario:

# 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 

Al lanzar test_wait_app_up_fail, la duración de tiempo de espera actual es de 3 segundos.

2

Quería publicar una respuesta de que hay un caso donde no se encontrará la variable.

Las importaciones cíclicas pueden interrumpir el comportamiento del módulo.

Por ejemplo:

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 

en esto es ejemplo debería ser obvio, pero en una gran base de código, esto puede ser r eally confuso.

Cuestiones relacionadas