80

I am relatively new to Python. I am looking to create a "settings" module where various application-specific constants will be stored.

Here is how I am wanting to set up my code:

settings.py

CONSTANT = 'value'

script.py

import settings

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

I am getting a Python error stating:

global name 'CONSTANT' is not defined.

I have noticed on Django's source code their settings.py file has constants named just like I do. I am confused on how they can be imported to a script and referenced through the application.

EDIT

Thank you for all your answers! I tried the following:

import settings

print settings.CONSTANT

I get the same error

ImportError: cannot import name CONSTANT

Maximilian Burszley
  • 18,243
  • 4
  • 34
  • 63
Lark
  • 4,654
  • 7
  • 33
  • 34
  • 5
    That makes not sense. you should be getting an `AttributeError` if `settings` doesn't define `CONSTANT` and an `ImportError` if it can't import settings, in which case it wouldn't even look at `CONSTANT` – aaronasterling Sep 29 '10 at 19:07
  • Is there something I am doing wrong then? – Lark Sep 29 '10 at 19:14
  • 1
    Put the two lines that you posted last in a file by it self exactly as you posted them and see if it works. – aaronasterling Sep 29 '10 at 20:58
  • 1
    Thank you everyone for all your help. I figured it out. It had to do with the placement of the __init__.py file. I was trying to import settings so python was looking couldn't find it so once I referenced the "modules" directory settings was in, everything worked properly. So basically my import statement looks like this: from modules import settings. I think there is a better way to do this, a more pythonic, so I am going to try different combinations. Again thank you for all your answers. – Lark Sep 30 '10 at 11:26

10 Answers10

144

The easiest way to do this is to just have settings be a module.

(settings.py)

CONSTANT1 = "value1"
CONSTANT2 = "value2"

(consumer.py)

import settings

print settings.CONSTANT1
print settings.CONSTANT2

When you import a python module, you have to prefix the the variables that you pull from it with the module name. If you know exactly what values you want to use from it in a given file and you are not worried about them changing during execution, then you can do

from settings import CONSTANT1, CONSTANT2

print CONSTANT1
print CONSTANT2

but I wouldn't get carried away with that last one. It makes it difficult for people reading your code to tell where values are coming from. and precludes those values being updated if another client module changes them. One final way to do it is

import settings as s

print s.CONSTANT1
print s.CONSTANT2

This saves you typing, will propagate updates and only requires readers to remember that anything after s is from the settings module.

aaronasterling
  • 68,820
  • 20
  • 127
  • 125
  • @delnan I specifically avoided mentioning the mechanics so as to not make your answer obsolete ;) – aaronasterling Sep 29 '10 at 18:11
  • Well, practically obsolete ;) Knowing the exact semantics is useful and preferable, but to make it work, it's not needed - though it is necessary to know the implications of it, which are pretty much summarzied in your answer. –  Sep 29 '10 at 18:16
  • 3
    I though the idea of constant is that it cannot be changed on runtime? – Lie Ryan Sep 30 '10 at 11:40
  • 1
    @Lie Ryan, Python doesn't have constants. On multiprogrammer projects, you never know. – aaronasterling Sep 30 '10 at 11:51
  • 1
    @AaronMcSmoot: yes, but if you even have the intention to change a constant after runtime, that's very suspect that you've got the wrong design. – Lie Ryan Oct 01 '10 at 05:05
  • @Lie Ryan. I'm not sure that I entirely agree. 'setting' is a more accurate term than 'constant' in python and why can't settings change so long as all client code is aware of it? Regardless though, the fact that it's a possibility means that it should be taken into account – aaronasterling Oct 01 '10 at 05:29
  • @AaronMcSmooth: settings != CONSTANTS. Changing constants at runtime does not make sense. IMO, if you take into account the possibility of changing a constant, then you're overdesigning. OTOH, settings are meant to be changed on runtime; but settings shouldn't use ALLCAPS, otherwise you're nullifying the advantage of having constants written in ALLCAPS. – Lie Ryan Oct 01 '10 at 07:09
  • @Lie Ryan. about the overdesign. When the only thing that i'm advocating is that those changes (if they occur) propagate, then I don't think that's overdesign. Especially not if it dovetails with what is otherwise a best practive, such as avoiding barenames. It makes mocking for tests easier, for instance. – aaronasterling Oct 01 '10 at 07:33
  • @AaronMcSmooth: what I'm trying to say is, that those changes should not happen at all. If there is a change in the value of a constant, then it's a bug; either in the design or in the program itself. Why would you want to have a different constant values when testing? They should never change, period. You should never assign to an ALLCAPS name, except once when declaring the constant. There is no need to design it for the possibility of changing it. – Lie Ryan Oct 01 '10 at 08:44
18

step 1: create a new file settings.py on the same directory for easier access.

#database configuration settings

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

#application predefined constants

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

step 2: importing settings module into your application file.

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

if you do not like to use alias like s you can use a different syntax

from settings import database, app

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

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

notice on the second import method you can use the dict names directly

A small tip you can import all the code on the settings file by using * in case you have a large file and you will be using most of the settings on it on your application

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

i hope that helps.

Fady Faried
  • 291
  • 3
  • 4
5

When you import settings, a module object called settings is placed in the global namespace - and this object carries has that was in settings.py as attributes. I.e. outside of settings.py, you refer to CONSTANT as settings.CONSTANT.

4

Leave your settings.py exactly as it is, then you can use it just as Django does:

import settings

def func():
    var = settings.CONSTANT
MikeW
  • 5,504
  • 1
  • 34
  • 29
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
3

...Or, if you really want all the constants from settings.py to be imported into the global namespace, you can run

from settings import *

...but otherwise using settings.CONSTANT, as everyone else has mentioned here, is quite right.

ewall
  • 27,179
  • 15
  • 70
  • 84
  • See my answer for all three possible ways to use the `import` statement. – aaronasterling Sep 29 '10 at 18:15
  • 2
    Actually, this is not advisable. See e.g. http://docs.python.org/howto/doanddont.html#from-module-import. Although in this case it has the propably desirable side effect that changes to the constants won't affect other modules. –  Sep 29 '10 at 18:18
  • 2
    Nicely said, @AaronMcSmooth. And technically I didn't say it was advisable to import *, just that it was possible :P – ewall Sep 29 '10 at 18:21
  • @delnan. I'm not so sure that that's desirable. It depends on the application but It could just as likely be that changes should be propagated (if they even occur) – aaronasterling Sep 29 '10 at 18:21
3

See the answer I posted to Can I prevent modifying an object in Python? which does what you want (as well as force the use of UPPERCASE identifiers). It might actually be a better answer for this question than it was for the the other.

Community
  • 1
  • 1
martineau
  • 119,623
  • 25
  • 170
  • 301
3

This way is more efficient since it loads/evaluates your settings variables only once. It works well for all my Python projects.

pip install python-settings

Docs here: https://github.com/charlsagente/python-settings

You need a settings.py file with all your defined constants like:

# settings.py

DATABASE_HOST = '10.0.0.1'

Then you need to either set an env variable (export SETTINGS_MODULE=settings) or manually calling the configure method:

# 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

The utility also supports Lazy initialization for heavy to load objects, so when you run your python project it loads faster since it only evaluates the settings variable when its needed

# 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)

Just configure once and now call your variables where is needed:

# my_awesome_file.py

from python_settings import settings 

print(settings.DATABASE_HOST) # Will print '10.0.0.1'
charls
  • 39
  • 2
2

I'm new in python but if we define an constant like a function on setings.py

def CONST1():
    return "some value"

main.py

import setings

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

here I see only one, value cant be changed but its work like a function..

Anthon
  • 69,918
  • 32
  • 186
  • 246
IVI
  • 139
  • 7
1

Try this:

In settings.py:

CONSTANT = 5

In your main file:

from settings import CONSTANT

class A:
    b = CONSTANT

    def printb(self):
         print self.b

I think your above error is coming from the settings file being imported too late. Make sure it's at the top of the file.

kcunning
  • 297
  • 1
  • 4
1

Also worth checking out is the simple-settings project which allows you to feed the settings into your script at runtim, which allows for environment-specific settings (think dev, test, prod,...)

Gregor
  • 1,297
  • 1
  • 19
  • 31