Pregunta

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?

La variable (seamos originales y la llamemos 'foo') no tiene que ser verdaderamente 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 ellos.

¿Fue útil?

Solución

No apoyo esta solución de ninguna manera, forma o forma. Pero si agrega una variable al módulo __builtin__ , será accesible como un módulo global desde 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 " 1 " está impreso.

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

Otros consejos

Si necesita una variable global de módulos cruzados, tal vez una simple variable global a nivel de módulo sea suficiente.

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

Ejemplo del mundo real: global_settings.py (aunque en Django, las configuraciones se usan importando el objeto django.conf.settings ).

Defina un módulo (llámelo " globalbaz ") y tenga las variables definidas dentro de él. Todos los módulos que utilizan este " pseudoglobal " debe importar el " globalbaz " módulo, y consúltelo utilizando " 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 utilizará el último valor. (Probé esto en un ejemplo de juguete)

Para aclaraciones, globalbaz.py se ve así:

var_name = "my_useful_string"

Creo que hay muchas circunstancias en las que tiene sentido y simplifica la programación para tener algunos globales conocidos a través de varios módulos (estrechamente acoplados). En este sentido, me gustaría elaborar un poco sobre la idea de tener un módulo de elementos globales que sea importado por aquellos módulos que necesitan hacer referencia a ellos.

Cuando solo hay un módulo de este tipo, lo nombro " g " ;. En él, asigno valores predeterminados para cada variable que pretendo tratar como global. En cada módulo que utiliza alguno de ellos, no uso " 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 en la " g. & Quot; sirve como un recordatorio constante de que estoy tratando con una variable que es potencialmente accesible a otros módulos.

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

Tenga en cuenta que también puede tener varios 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 sobrecargar el código con las ocurrencias de ellos. Con solo un poco de experiencia, se vuelven lo suficientemente mnemotécnicos con solo 1 o 2 caracteres.

Todavía es posible realizar una asignación a, por ejemplo, g.x cuando x no estaba ya definida 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 asignación. A veces, un examen de dir (g) es útil para descubrir cualquier nombre sorpresa que pueda haber surgido por tal accidente.

Puede pasar los globales de un módulo a otro:

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

Las variables globales suelen ser una mala idea, pero puedes hacerlo asignando a __builtins__ :

__builtins__.foo = 'something'
print foo

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

# my_globals.py
foo = 'something'

Luego puedes usar eso desde cualquier lugar también:

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.

Ya puedes hacer esto con variables de nivel de módulo. Los módulos son los mismos sin importar de qué módulo se estén importando. Por lo tanto, puede hacer de la variable una variable de nivel de módulo en cualquier módulo en el que tenga sentido colocarla, y acceder a ella o asignarla desde otros módulos. Sería mejor llamar a una función para establecer el valor de la variable, o convertirla en una propiedad de algún objeto singleton. De esa forma, si terminas necesitando ejecutar algún código cuando la variable cambia, puedes hacerlo sin romper la interfaz externa de tu módulo.

Por lo general, no es una buena forma de hacer las cosas, ya que usar globals rara vez lo es, pero creo que es la forma más limpia de hacerlo.

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

Las importaciones cíclicas pueden romper 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 este ejemplo, debería ser obvio, pero en una base de código grande, esto puede ser realmente confuso.

Esto suena como modificar el espacio de nombre __builtin__ . Para hacerlo:

import __builtin__
__builtin__.foo = 'some-value'

No use el __builtins__ directamente (observe los " s ") adicionales - aparentemente, esto puede ser un diccionario o un módulo. Gracias a & # 932; & # 918; & # 937; & # 932; & # 918; & # 921; & # 927; & # 933; para señalar esto, se puede encontrar más información aquí .

Ahora foo está disponible para su uso en todas partes.

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

La asignación se debe hacer como se indicó anteriormente, solo configurando foo = 'algún otro valor' solo lo establecerá en el espacio de nombres actual.

Lo uso para un par de funciones primitivas integradas que sentí que realmente faltaban. Un ejemplo es una función de búsqueda que tiene la misma semántica de uso que filtro, mapa, reducir.

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 se ejecuta (por ejemplo, al importar cerca de su punto de entrada), todos sus módulos pueden usar find () como si, obviamente, se integrara.

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

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

Podría lograr variables modificables entre módulos (o mutables ) utilizando 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 iniciar test_wait_app_up_fail , la duración real del tiempo de espera es de 3 segundos.

Me pregunté si sería posible evitar algunas de las desventajas de usar variables globales (ver, por ejemplo, http: //wiki.c2.com/?GlobalVariablesAreBad ) usando un espacio de nombres de clase en lugar de un espacio de nombres global / módulo para pasar valores de variables. El siguiente código indica que los dos métodos son esencialmente idénticos. Hay una ligera ventaja en el uso de espacios de nombres de clase como se explica a continuación.

Los siguientes fragmentos de código también muestran que los atributos o variables pueden crearse y eliminarse dinámicamente tanto en los espacios de nombres globales / de módulos como en los espacios de nombres de clases.

wall.py

# Note no definition of global variables

class router:
    """ Empty class """

Yo llamo a este módulo 'muro' porque se usa para rebotar variables. Actuará como un espacio para definir temporalmente variables globales y atributos de toda la clase de la clase vacía 'router'.

source.py

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

Este módulo importa un muro y define una función única sourcefn que define un mensaje y lo emite mediante dos mecanismos diferentes, uno a través de globales y otro a través de la función de enrutador. Tenga en cuenta que las variables wall.msg y wall.router.message se definen aquí por primera vez en sus respectivos espacios de nombres.

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'

Este módulo define una función destfn que utiliza los dos mecanismos diferentes para recibir los mensajes emitidos por la fuente. Permite la posibilidad de que la variable 'msg' no exista. destfn también elimina las variables una vez que se han mostrado.

main.py

import source, dest

source.sourcefn()

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

Este módulo llama a las funciones previamente definidas en secuencia. Después de la primera llamada a dest.destfn , las variables wall.msg y wall.router.msg ya no existen.

La salida del programa es:

global: ¡Hola mundo!
enrutador: ¡Hola mundo!
global: ningún mensaje
enrutador: no hay mensaje

Los fragmentos de código anteriores muestran que el módulo / global y los mecanismos de variable de clase / clase son esencialmente idénticos.

Si se van a compartir muchas variables, la contaminación del espacio de nombres se puede administrar mediante el uso de varios módulos de tipo pared, por ejemplo. wall1, wall2 etc. o definiendo varias clases de tipo enrutador en un solo archivo. Este último es ligeramente más ordenado, por lo que quizás representa una ventaja marginal para el uso del mecanismo de clase-variable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top