¿Crear constantes usando un módulo de "configuración"?

78

Soy relativamente nuevo en Python. Estoy buscando crear un módulo de "configuración" donde se almacenarán varias constantes específicas de la aplicación.

Así es como quiero configurar mi código:

settings.py

CONSTANT = 'value'

script.py

import settings

def func():
    var = CONSTANT
    # do some more coding
    return var

Recibo un error de Python que indica:

global name 'CONSTANT' is not defined.

He notado que en el código fuente de Django, su settings.pyarchivo tiene constantes nombradas como yo. Estoy confundido sobre cómo se pueden importar a un script y hacer referencia a ellos a través de la aplicación.

EDITAR

¡Gracias por todas tus respuestas! Intenté lo siguiente:

import settings

print settings.CONSTANT

Me sale el mismo error

ImportError: cannot import name CONSTANT

Alondra
fuente
5
Eso no tiene sentido. debería obtener un AttributeErrorif settingsno define CONSTANTy un ImportErrorif no puede importar configuraciones, en cuyo caso ni siquiera miraríaCONSTANT
aaronasterling
¿Hay algo que esté haciendo mal entonces?
Lark
1
Coloque las dos líneas que publicó por última vez en un archivo por sí mismo exactamente como las publicó y vea si funciona.
aaronasterling
1
Gracias a todos por toda su ayuda. Me lo imaginé. Tenía que ver con la ubicación del archivo init .py. Estaba tratando de importar la configuración, por lo que Python no podía encontrarla, así que una vez que hice referencia a la configuración del directorio "módulos", todo funcionó correctamente. Entonces, básicamente, mi declaración de importación se ve así: desde la configuración de importación de módulos. Creo que hay una mejor manera de hacer esto, una más pitónica, así que voy a probar diferentes combinaciones. Nuevamente gracias por todas sus respuestas.
Lark

Respuestas:

140

La forma más sencilla de hacer esto es simplemente hacer que la configuración sea un módulo.

(settings.py)

CONSTANT1 = "value1"
CONSTANT2 = "value2"

(consumer.py)

import settings

print settings.CONSTANT1
print settings.CONSTANT2

Cuando importa un módulo de Python, debe anteponer el nombre del módulo a las variables que extrae de él. Si sabe exactamente qué valores desea usar de él en un archivo determinado y no le preocupa que cambien durante la ejecución, puede hacerlo

from settings import CONSTANT1, CONSTANT2

print CONSTANT1
print CONSTANT2

pero no me dejaría llevar por ese último. Hace que sea difícil para las personas que leen su código saber de dónde provienen los valores. e impide que esos valores se actualicen si otro módulo de cliente los cambia. Una última forma de hacerlo es

import settings as s

print s.CONSTANT1
print s.CONSTANT2

Esto le ahorra escribir, propagará actualizaciones y solo requiere que los lectores recuerden que todo lo que sviene después es del módulo de configuración.

aaronasterling
fuente
@delnan Evité específicamente mencionar la mecánica para no hacer que su respuesta sea obsoleta;)
aaronasterling
Bueno, prácticamente obsoleto;) Conocer la semántica exacta es útil y preferible, pero para que funcione, no es necesario, aunque es necesario conocer sus implicaciones, que se resumen bastante en su respuesta.
3
Pensé que la idea de constante es que no se puede cambiar en tiempo de ejecución.
Lie Ryan
1
@Lie Ryan, Python no tiene constantes. En proyectos multiprogramadores, nunca se sabe.
aaronasterling
1
@AaronMcSmoot: sí, pero si incluso tiene la intención de cambiar una constante después del tiempo de ejecución, es muy sospechoso que tenga el diseño incorrecto.
Lie Ryan
17

Paso 1: cree un nuevo archivo settings.py en el mismo directorio para facilitar el acceso.

#database configuration settings

database = dict(
    DATABASE = "mysql",
    USER     = "Lark",
    PASS     = ""
)

#application predefined constants

app = dict(
    VERSION   = 1.0,
    GITHUB    = "{url}"
)

Paso 2: importar el módulo de configuración a su archivo de aplicación.

import settings as s            # s is aliasing settings & settings is the actual file you do not have to add .py 

print(s.database['DATABASE'])   # should output mysql

print(s.app['VERSION'])         # should output 1.0

si no le gusta usar alias como s, puede usar una sintaxis diferente

from settings import database, app

print(database['DATABASE'])   # should output mysql

print(app['VERSION'])         # should output 1.0

aviso sobre el segundo método de importación puede utilizar los nombres de dictado directamente

Un pequeño consejo : puede importar todo el código en el archivo de configuración usando * en caso de que tenga un archivo grande y usará la mayoría de las configuraciones en su aplicación

from settings import *      # * represent all the code on the file, it will work like step 2


print(database['USER'])       # should output lark

print(app['VERSION'])         # should output 1.0

Espero que eso ayude.

Fady Faried
fuente
5

Cuando usted import settings, un moduleobjeto llamado settingsse coloca en el espacio de nombres global, y este objeto lleva settings.pycomo atributos. Es decir, fuera de settings.py, te refieres CONSTANTcomo settings.CONSTANT.


fuente
4

Deje su settings.py exactamente como está, luego puede usarlo tal como lo hace Django:

import settings

def func():
    var = settings.CONSTANT
Ned Batchelder
fuente
3

... O, si realmente desea que todas las constantes de settings.py se importen al espacio de nombres global, puede ejecutar

from settings import *

... pero de otra manera usar settings.CONSTANT, como todos los demás han mencionado aquí, es bastante correcto.

ewall
fuente
Consulte mi respuesta para conocer las tres formas posibles de usar la importdeclaración.
aaronasterling
2
De hecho, esto no es recomendable. Consulte, por ejemplo, docs.python.org/howto/doanddont.html#from-module-import . Aunque en este caso tiene el efecto secundario probablemente deseable de que los cambios en las constantes no afectarán a otros módulos.
2
Bien dicho, @AaronMcSmooth. Y técnicamente no dije que fuera aconsejable importar *, solo que era posible: P
ewall
@delnan. No estoy tan seguro de que eso sea deseable. Depende de la aplicación, pero también podría ser probable que los cambios se propaguen (si es que ocurren)
aaronasterling
3

Vea la respuesta que publiqué en ¿Puedo evitar modificar un objeto en Python? que hace lo que quieres (además de forzar el uso de identificadores MAYÚSCULAS). De hecho, podría ser una mejor respuesta para esta pregunta que para la otra.

martineau
fuente
2

Soy nuevo en Python, pero si definimos una constante como una función en setings.py

def CONST1():
    return "some value"

main.py

import setings

print setings.CONST1() ##take an constant value

aquí solo veo uno, el valor no se puede cambiar pero funciona como una función.

IVI
fuente
2

De esta manera es más eficiente ya que carga / evalúa sus variables de configuración solo una vez. Funciona bien para todos mis proyectos de Python.

pip install python-settings

Documentos aquí: https://github.com/charlsagente/python-settings

Necesita un archivo settings.py con todas sus constantes definidas como:

# settings.py

DATABASE_HOST = '10.0.0.1'

Luego, debe establecer una variable env (exportar SETTINGS_MODULE = settings) o llamar manualmente al método de configuración:

# something_else.py

from python_settings import settings
from . import settings as my_local_settings

settings.configure(my_local_settings) # configure() receives a python module

La utilidad también admite la inicialización perezosa para objetos pesados, por lo que cuando ejecuta su proyecto de Python, se carga más rápido ya que solo evalúa la variable de configuración cuando es necesario

# settings.py

from python_settings import LazySetting
from my_awesome_library import HeavyInitializationClass # Heavy to initialize object

LAZY_INITIALIZATION = LazySetting(HeavyInitializationClass, "127.0.0.1:4222") 
# LazySetting(Class, *args, **kwargs)

Simplemente configure una vez y ahora llame a sus variables donde sea necesario:

# my_awesome_file.py

from python_settings import settings 

print(settings.DATABASE_HOST) # Will print '10.0.0.1'
charls
fuente
1

Prueba esto:

En settings.py:

CONSTANT = 5

En su archivo principal:

from settings import CONSTANT

class A:
    b = CONSTANT

    def printb(self):
         print self.b

Creo que el error anterior proviene de la importación del archivo de configuración demasiado tarde. Asegúrese de que esté en la parte superior del archivo.

astucia
fuente
1

También vale la pena echarle un vistazo al proyecto de configuración simple que le permite introducir la configuración en su script en runtim, lo que permite configuraciones específicas del entorno (piense en dev, test, prod, ...)

Gregor
fuente