Python Global Constant

Discussion in 'Python' started by Krisztian Kepes, Jul 9, 2003.

  1. 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
    Krisztian Kepes, Jul 9, 2003
    #1
    1. Advertising

  2. Krisztian Kepes

    Peter Hansen Guest

    Krisztian Kepes wrote:
    >
    > 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
    Peter Hansen, Jul 9, 2003
    #2
    1. Advertising


  3. >>*** 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 ........


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


    cbf
    Christoph Becker-Freyseng, Jul 9, 2003
    #3
  4. Krisztian Kepes

    Ulrich Petri Guest

    "Peter Hansen" <> schrieb im Newsbeitrag
    news:...
    > Krisztian Kepes wrote:
    >
    > > *** 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.


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

    Ciao Ulrich
    Ulrich Petri, Jul 9, 2003
    #4
  5. Krisztian Kepes

    Peter Hansen Guest

    Christoph Becker-Freyseng wrote:
    >
    > >>*** 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 ........

    >
    > 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
    Peter Hansen, Jul 9, 2003
    #5
  6. Krisztian Kepes

    Terry Reedy Guest


    > 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
    Terry Reedy, Jul 9, 2003
    #6
  7. Peter Hansen wrote:
    > 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. :)

    --
    Greg Ewing, Computer Science Dept,
    University of Canterbury,
    Christchurch, New Zealand
    http://www.cosc.canterbury.ac.nz/~greg
    Greg Ewing (using news.cis.dfn.de), Jul 10, 2003
    #7
  8. Krisztian Kepes

    Jp Calderone Guest

    On Thu, Jul 10, 2003 at 04:06:55PM +1200, Greg Ewing (using news.cis.dfn.de) wrote:
    > Peter Hansen wrote:
    > >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

    --
    "The problem is, of course, that not only is economics bankrupt but it has
    always been nothing more than politics in disguise ... economics is a form
    of brain damage." -- Hazel Henderson
    Jp Calderone, Jul 10, 2003
    #8
  9. On Thu, 10 Jul 2003 02:01:47 -0400, Jp Calderone <> wrote:

    >On Thu, Jul 10, 2003 at 04:06:55PM +1200, Greg Ewing (using news.cis.dfn.de) wrote:
    >> Peter Hansen wrote:
    >> >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 ?
    File "<string>", line 11, in __setattr__
    TypeError: module MyConsts is read-only
    >>> setattr(MyConsts,'foo',123)

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<string>", line 11, in __setattr__
    TypeError: module MyConsts is read-only
    >>> 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__')

    <class 'makeconst.MyConsts'>
    >>> object.__getattribute__(MyConsts,'__class__').__dict__

    <dict-proxy object at 0x007DD6F0>
    >>> 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
    >>> object.__setattr__(MyConsts,'PI','Cherry ;-)')


    Not this way:
    >>> MyConsts.PI

    3.1415000000000002

    But this way:
    >>> object.__getattribute__(MyConsts,'PI')

    'Cherry ;-)'

    We can see it in the instance dict that was created:
    >>> object.__getattribute__(MyConsts,'__dict__')

    {'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:

    >>> MyConsts.PI

    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
    Bengt Richter, Jul 11, 2003
    #9
  10. Re: Python Global Constant; __builtins__

    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
    Christoph Becker-Freyseng, Jul 12, 2003
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Christopher M. Lusardi
    Replies:
    1
    Views:
    4,086
  2. Martin Magnusson
    Replies:
    2
    Views:
    503
    John Harrison
    Oct 8, 2004
  3. Tor Erik Soenvisen
    Replies:
    14
    Views:
    558
    Tim Roberts
    Nov 23, 2006
  4. Replies:
    4
    Views:
    338
    Keith Thompson
    Dec 14, 2006
  5. Replies:
    13
    Views:
    12,921
    Kai-Uwe Bux
    Jan 22, 2007
Loading...

Share This Page