variable utiliza tipos texto que modulos lista imprimir funciones declarar datos como python variables singleton module scope

texto - tipos de datos que utiliza python



¿Cómo crear variables de módulo completo en Python? (5)

Aquí es donde está pasando.

En primer lugar, las únicas variables globales que Python realmente tiene son las variables con ámbito de módulo. No puedes hacer una variable que sea verdaderamente global; Todo lo que puedes hacer es crear una variable en un ámbito particular. (Si crea una variable dentro del intérprete de Python y luego importa otros módulos, su variable estará en el alcance más externo y, por lo tanto, será global en su sesión de Python).

Todo lo que tiene que hacer para crear una variable módulo global es simplemente asignarle un nombre.

Imagine un archivo llamado foo.py, que contiene esta única línea:

X = 1

Ahora imagina que lo importas.

import foo print(foo.X) # prints 1

Sin embargo, supongamos que desea utilizar una de sus variables de ámbito de módulo como global dentro de una función, como en su ejemplo. El valor predeterminado de Python es suponer que las variables de función son locales. Simplemente agrega una declaración global en su función, antes de intentar usar el global.

def initDB(name): global __DBNAME__ # add this line! if __DBNAME__ is None: # see notes below; explicit test for None __DBNAME__ = name else: raise RuntimeError("Database name has already been set.")

Por cierto, para este ejemplo, la prueba simple if not __DBNAME__ es adecuada, porque cualquier valor de cadena que no sea una cadena vacía evaluará verdadero, por lo que cualquier nombre de base de datos real evaluará verdadero. Pero para las variables que podrían contener un valor numérico que podría ser 0, no se puede decir if not variablename ; en ese caso, debe probar explícitamente None utilizando el operador is . Modifiqué el ejemplo para agregar una prueba None explícita. La prueba explícita de None nunca es incorrecta, por lo que de manera predeterminada la uso.

Finalmente, como han señalado otros en esta página, dos puntos destacados señalan a Python que desea que la variable sea "privada" para el módulo. Si alguna vez realiza una import * from mymodule , Python no importará nombres con dos guiones bajos principales en su espacio de nombres. Pero si solo hace una import mymodule y luego dice dir(mymodule) verá las variables "privadas" en la lista, y si se refiere explícitamente a mymodule.__DBNAME__ Python no le importará, solo le permitirá consultar eso. Los guiones bajos dobles son una pista importante para los usuarios de su módulo de que no desea que vuelvan a enlazar ese nombre con algún valor propio.

Se considera una práctica recomendada en Python no import * , sino minimizar el acoplamiento y maximizar la explicitud ya sea al utilizar mymodule.something o al hacer explícitamente una importación como from mymodule import something .

EDITAR: si, por alguna razón, necesita hacer algo como esto en una versión muy antigua de Python que no tiene la palabra clave global , existe una solución fácil. En lugar de establecer directamente una variable global de módulo, use un tipo mutable en el nivel global del módulo y almacene sus valores dentro de él.

En sus funciones, el nombre de la variable global será de solo lectura; no podrá volver a enlazar el nombre de la variable global real. (Si asigna un nombre de variable dentro de su función, solo afectará el nombre de la variable local dentro de la función). Pero puede usar ese nombre de variable local para acceder al objeto global real y almacenar datos dentro de él.

Puedes usar una list pero tu código será feo:

__DBNAME__ = [None] # use length-1 list as a mutable # later, in code: if __DBNAME__[0] is None: __DBNAME__[0] = name

Un dict es mejor. Pero lo más conveniente es una instancia de clase, y puedes usar una clase trivial:

class Box: pass __m = Box() # m will contain all module-level values __m.dbname = None # database name global in module # later, in code: if __m.dbname is None: __m.dbname = name

(Realmente no necesita capitalizar la variable del nombre de la base de datos).

Me gusta el azúcar sintáctico de usar __m.dbname lugar de __m["DBNAME"] ; parece la solución más conveniente en mi opinión. Pero la solución dict funciona bien también.

Con un dict puede usar cualquier valor hashable como clave, pero cuando esté satisfecho con los nombres que son identificadores válidos, puede usar una clase trivial como Box en el párrafo anterior.

¿Hay alguna manera de configurar una variable global dentro de un módulo? Cuando traté de hacerlo de la forma más obvia como aparece a continuación, el intérprete de Python dijo que la variable __DBNAME__ no existía.

... __DBNAME__ = None def initDB(name): if not __DBNAME__: __DBNAME__ = name else: raise RuntimeError("Database name has already been set.") ...

Y después de importar el módulo en un archivo diferente

... import mymodule mymodule.initDB(''mydb.sqlite'') ...

Y el rastreo fue: UnboundLocalError: local variable ''__DBNAME__'' referenced before assignment

¿Algunas ideas? Estoy tratando de configurar un singleton usando un módulo, según la recomendación de este compañero .


La respuesta de Steveha fue útil para mí, pero omite un punto importante (uno en el que creo que wisty estaba llegando). La palabra clave global no es necesaria si solo accede pero no asigna la variable en la función.

Si asigna la variable sin la palabra clave global, Python crea una nueva var local: el valor de la variable del módulo ahora estará oculto dentro de la función. Use la palabra clave global para asignar el módulo var dentro de una función.

Pylint 1.3.1 en Python 2.7 exige que NO se use global si no se asigna la var.

module_var = ''/dev/hello'' def readonly_access(): connect(module_var) def readwrite_access(): global module_var module_var = ''/dev/hello2'' connect(module_var)


Para esto, necesita declarar la variable como global. Sin embargo, también se puede acceder a una variable global desde fuera del módulo utilizando module_name.var_name . Agregue esto como la primera línea de su módulo:

global __DBNAME__


Te estás enamorando de una sutil peculiaridad. No puede volver a asignar variables de nivel de módulo dentro de una función de Python. Creo que esto está ahí para evitar que las personas vuelvan a asignar cosas dentro de una función por accidente.

Puede acceder al espacio de nombres del módulo, simplemente no debe intentar reasignar. Si su función asigna algo, se convierte automáticamente en una variable de función, y Python no buscará en el espacio de nombres del módulo.

Tu puedes hacer:

__DB_NAME__ = None def func(): if __DB_NAME__: connect(__DB_NAME__) else: connect(Default_value)

pero no puedes volver a asignar __DB_NAME__ dentro de una función.

Una solución:

__DB_NAME__ = [None] def func(): if __DB_NAME__[0]: connect(__DB_NAME__[0]) else: __DB_NAME__[0] = Default_value

Tenga en cuenta que no estoy reasignando __DB_NAME__ , solo estoy modificando su contenido.


Acceso explícito a las variables de nivel de módulo accediendo a ellas explícitamente en el módulo

En resumen: la técnica descrita aquí es la misma que en la respuesta de steveha , excepto que no se crea ningún objeto auxiliar artificial para hacer un alcance explícito de las variables. En cambio, al objeto del módulo en sí se le asigna un puntero variable y, por lo tanto, proporciona un alcance explícito al acceder desde cualquier lugar. (como asignaciones en el alcance de la función local) .

¡Piense en él como en el módulo actual en lugar de la instancia actual!

# db.py import sys # this is a pointer to the module object instance itself. this = sys.modules[__name__] # we can explicitly make assignments on it this.db_name = None def initialize_db(name): if (this.db_name is None): # also in local function scope. no scope specifier like global is needed this.db_name = name # also the name remains free for local use db_name = "Locally scoped db_name variable. Doesn''t do anything here." else: msg = "Database is already initialized to {0}." raise RuntimeError(msg.format(this.db_name))

Como los módulos se almacenan en caché y, por lo tanto, se importan solo una vez , puede importar db.py veces como desee, manipulando el mismo estado universal:

# client_a.py import db db.initialize_db(''mongo'')

# client_b.py from db import db_name if (db_name == ''mongo''): db_name = None

He utilizado esta receta para crear módulos manejadores simples y livianos (a diferencia de las clases de controladores) desde que lo encontré. Como una ventaja adicional, creo que es bastante pitonica en general, ya que encaja muy bien con la política de Pythons de Explicit es mejor que implícita .