Python Global Constant

  • Thread starter Krisztian Kepes
  • Start date
K

Krisztian Kepes

Hi !

I want to create an module and I want to use some Global Constant in it.
How to I create an global constant in module what is accessable in from other modules ?

like this example:

*** module dirs ***
const Const_Up=1
const Const_Down=1

*** module any ***
import dirs;
def CheckDir(Dir):
if Dir=dirs.Const_Up: xxx

?????

Thx:
Chris
 
P

Peter Hansen

Krisztian said:
I want to create an module and I want to use some Global Constant in it.
How to I create an global constant in module what is accessable in from other modules ?

like this example:

*** module dirs ***
const Const_Up=1
const Const_Down=1

Just do what you did above, without the "const" modifier, which
doesn't exist and is not really needed in Python.
*** module any ***
import dirs;
def CheckDir(Dir):
if Dir=dirs.Const_Up: xxx

This code should work fine, although you might want to follow
the Python conventions for capitalization and formatting of
your code, to make it more readable for others. For example,
variables and functions are generally mixed case, as in checkdir
or dir, while constants are usually ALLCAPS as in CONST_UP.

-Peter
 
C

Christoph Becker-Freyseng

This code should work fine, although you might want to follow
the Python conventions ........

What about using __builtins__ wouldn't make this the constant really global?


cbf
 
U

Ulrich Petri

Peter Hansen said:
This code should work fine, although you might want to follow
the Python conventions for capitalization and formatting of
your code, to make it more readable for others. For example,
variables and functions are generally mixed case, as in checkdir
or dir, while constants are usually ALLCAPS as in CONST_UP.

No it wont. "if Dir = dirs.Const_Up:" is invalid syntax (Note the = instead
of ==)

Ciao Ulrich
 
P

Peter Hansen

Christoph said:
What about using __builtins__ wouldn't make this the constant really global?

A module is already global, in the sense that if you do "import xxx"
you will get a reference to a singleton module object (generally from
xxx.py), which provides a nice clean namespace for a set of names such
as constants.

This makes it easy for someone reading the code to see where a constant
is defined, and it provides a necessary level of organization.

Putting something in __builtins__ is not only stylistically a bad
idea for most things, but it also hides the source of the name and
anyone reading the file will be at a loss to figure out where it
came from unless every reference to it is preceded by a big comment::

# WARNING! The author of this code chose the silly approach
# of storing a reference to this constant in the __builtins__
# namespace, which is why you can't find where it is defined.
# This reference was stored in the initialization code that
# is in init.py, and instead of just leaving the name there
# so you could call it "init.CONSTANT", it was slipped in
# through the back door to let the author save five keystrokes,
# at the expense of readability, but with this comment everything
# will be okay.
x = CONSTANT

How is that better than using the proper approach of storing constants
in a module, such as "constant.py"? ;-)

-Peter
 
T

Terry Reedy

What about using __builtins__ wouldn't make this the constant really
global?

Short respone: this is an implementation-detail-dependent hack that
Guido discourges and that Guido would be willing to break if there
were sufficient gain otherwise.

Longer answer: I once though of doing this too. However, the language
reference specifies module import as the means to make objects
globally accessible. I don't believe that the language reference
specifies the implementation details for the builtins namespace.
While currently
implemented as a user-writeble dict of the {} type, bound to the name
__builtins__, this could change.

Terry J. Reedy
 
G

Greg Ewing (using news.cis.dfn.de)

Peter said:
Just do what you did above, without the "const" modifier, which
doesn't exist and is not really needed in Python.

If you *really* insist on preventing anyone from changing
them, it is possible, with some hackery. Here's one way
that works:

#######################################################
#
# MyModule.py
#

_constants = ['PI', 'FortyTwo']

PI = 3.1415
FortyTwo = 42

import types

class _ConstModule(types.ModuleType):

__slots__ = []

def __setattr__(self, name, value):
if name in self.__dict__['_constants']:
raise ValueError("%s is read-only" % name)
self.__dict__[name] = value

del types
import MyModule
MyModule.__class__ = _ConstModule

#######################################################

Figuring out *how* it works is left as an exercise
for the student. :)
 
J

Jp Calderone

Peter said:
Just do what you did above, without the "const" modifier, which
doesn't exist and is not really needed in Python.

If you *really* insist on preventing anyone from changing
them, it is possible, with some hackery. Here's one way
that works:

#######################################################
#
# MyModule.py
#

_constants = ['PI', 'FortyTwo']

PI = 3.1415
FortyTwo = 42

import types

class _ConstModule(types.ModuleType):

__slots__ = []

def __setattr__(self, name, value):
if name in self.__dict__['_constants']:
raise ValueError("%s is read-only" % name)
self.__dict__[name] = value

del types
import MyModule
MyModule.__class__ = _ConstModule
>>> import MyModule
>>> del MyModule._constants[:]
>>> MyModule.PI = 'Cherry, please'
>>> MyModule.PI
'Cherry, please'

Jp
 
B

Bengt Richter

Peter said:
Just do what you did above, without the "const" modifier, which
doesn't exist and is not really needed in Python.

If you *really* insist on preventing anyone from changing
them, it is possible, with some hackery. Here's one way
that works:

#######################################################
#
# MyModule.py
#

_constants = ['PI', 'FortyTwo']

PI = 3.1415
FortyTwo = 42

import types

class _ConstModule(types.ModuleType):

__slots__ = []

def __setattr__(self, name, value):
if name in self.__dict__['_constants']:
raise ValueError("%s is read-only" % name)
self.__dict__[name] = value

del types
import MyModule
MyModule.__class__ = _ConstModule
import MyModule
del MyModule._constants[:]
MyModule.PI = 'Cherry, please'
MyModule.PI
'Cherry, please'

Jp
Ok, this one is a little more resistant, I think (though I'm not sure how much more ;-):
====< makeconst.py >=============================================================
import os, sys
def makeconst(m):
modulename = m.__name__
mpath = m.__file__
sfront = [
'def forclosure(m):',
' dictinclosure = {'
]
sback = [
' }',
' class %s(object):'% modulename,
' def __getattribute__(self, name):',
' if name=="__dict__": return dictinclosure.copy()', # no mods ;-)
' return dictinclosure[name]',
' def __setattr__(self,name,val):',
' raise TypeError, "module %s is read-only"'%modulename,
' return vars()["%s"]()'%modulename,
''
]
if mpath.endswith('.pyc'): mpath = mpath[:-1]
if not mpath.endswith('.py'):
raise ValueError, 'Not .py or .pyc based module: %s of %r'%(modulename, mpath)
for line in file(mpath):
line = line.strip()
if not line or line[0]=='#' or not line[0].isupper(): continue
lh,rh = map(str.strip, line.split('=',1))
sfront.append(
' %r:m.%s,'% (lh,lh) # get actual bindings from pre-constified module
)
exec '\n'.join(sfront+sback)
constmod = vars()['forclosure'](m)
sys.modules[modulename] = constmod
return constmod

def importconst(name): return makeconst(__import__(name))
=================================================================================

and we'll import and "make constant" the module:

====< MyConsts.py >====================================
#######################################################
#
# MyConsts.py
#

PI = 3.1415
FortyTwo = 42
=======================================================
>>> import makeconst
>>> MyConsts = makeconst.importconst('MyConsts')
>>> MyConsts.PI 3.1415000000000002
>>> dir(MyConsts) ['FortyTwo', 'PI']
>>> MyConsts.FortyTwo 42
>>> MyConsts.FortyTwo = 43
Traceback (most recent call last):
File "<stdin>", line 1, in ?
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File said:
>>> MyConsts.__dict__ {'PI': 3.1415000000000002, 'FortyTwo': 42}
>>> MyConsts.__dict__['PI'] = 'Cherry?'
>>> MyConsts.__dict__ {'PI': 3.1415000000000002, 'FortyTwo': 42}
>>> vars(MyConsts) {'PI': 3.1415000000000002, 'FortyTwo': 42}
>>> MyConsts.PI
3.1415000000000002

>>> object.__getattribute__(MyConsts,'__dict__') {}
>>> object.__getattribute__(MyConsts,'__class__')
>>> object.__getattribute__(MyConsts,'__class__').__dict__
>>> object.__getattribute__(MyConsts,'__class__').__dict__.keys() ['__module__', '__dict__', '__getattribute__', '__weakref__', '__setattr__', '__doc__']
>>> object.__getattribute__(MyConsts,'PI')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'MyConsts' object has no attribute 'PI'

Well, we can force one that will come back that way
Not this way: 3.1415000000000002

But this way: 'Cherry ;-)'

We can see it in the instance dict that was created: {'PI': 'Cherry ;-)'}

But not via the object normally:
>>> dir(MyConsts) ['FortyTwo', 'PI']
>>> MyConsts.__dict__ {'PI': 3.1415000000000002, 'FortyTwo': 42}
>>> getattr(MyConsts,'__dict__')
{'PI': 3.1415000000000002, 'FortyTwo': 42}

So you can force the instance to get a __dict__ with whatever apparent attribute, but you
can't make it apparent via normal attribute access, so it wouldn't affect modules importing
and using MyConsts normally:
3.1415000000000002

Well, some you can flesh out the special attributes/methods, but you get the drift.
We could also use a metaclass to fake the name exactly (when __name__ is returned ;-)
and in __repr__ and __str__.

If you import MyConsts after makeconst does its thing, I'm not sure how to sabotage the result of
the expression MyConsts.PI for other modules that have imported it, short of rebinding methods.
Since the data is not in a class variable or class dict, I you'd have to go after the closure cell.
I can find that (I think that's it below, though I'd have to print id(dictinclosure) to be sure),
e.g.,
>>> object.__getattribute__(MyConsts,'__class__').__getattribute__.im_func.func_closure[0]
<cell at 0x007D8FB0: dict object at 0x007DD5E0>

but how do you get at the dict in the cell? I don't guess it should be allowed, even if it's possible.

Otherwise you'll just have to mess with sys.modules similarly to get around it, I think, or accept
that you just have constant bindings (maybe to mutable objects though ;-)

Regards,
Bengt Richter
 
C

Christoph Becker-Freyseng

Hello,

Maybe I missunderstood the OP. So I said that __builtins__ might be
useful. I know that you should not use it in most cases because it makes
code less readable (where is xy defined?) and might cause unwanted
side-effects.
However e.g. if you're programming a big framework like Zope it is useful.

cbf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top