views:

138

answers:

4

The following python module is meant to be a basis for "constant" handling in python. The use case is the following:

  • one groups some constants (basically "names") that belong together with their values into a dictionary
  • with that dictionary bound to class variable a class is created and instantinated run-time
  • the attributes of this class are the constant names, their values are the constants themselves

Code:

class ConstantError(Exception):
    def __init__(self, msg):
        self._msg = msg

class Constant(object):
    def __init__(self, name):
        self._name = name
    def __get__(self, instance, owner):
        return owner._content[self._name]
    def __set__(self, instance, value):
        raise ConstantError, 'Illegal use of constant'

def make_const(name, content):
    class temp(object):
        _content = content
        def __init__(self):
            for k in temp._content:
                setattr(temp, k, Constant(k))

    temp.__name__ = name + 'Constant'
    return temp()

num_const = make_const('numeric', {
    'one': 1,
    'two': 2
})

str_const = make_const('string', {
    'one': '1',
    'two': '2'
})

Use:

>>> from const import *
>>> num_const
<const.numericConstant object at 0x7f03ca51d5d0>
>>> str_const
<const.stringConstant object at 0x7f03ca51d710>
>>> num_const.one
1
>>> str_const.two
'2'
>>> str_const.one = 'foo'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "const.py", line 16, in __set__
    raise ConstantError, 'Illegal use of constant'
const.ConstantError
>>>

Please, comment the design, implementation and correspondence to python coding guidelines.

+1  A: 

Most pythonic way is (to me):

my_fav_fruits = ('Apple', 'Orange', 'Strawberry', 'Chocolate Pudding')
lucky_numbers = (13, 7, 4, 99, 256)

Your design seems to bring some other languages features into python. You could do substitute of interface from java in similar fashion. Define a class that throws exceptions on any method call and make child classes derive from it and implement them. I seem to find that there is no point in doing stuff like that. My 'constants' work just as well as duck-typed behavior without interfaces (python docs are full of file-like objects).

Kugel
+1 for your are right, in Python it often comes down to just using the right mix of dicts, tuples and lists and you're done.
kaizer.se
"Your design seems to bring some other languages features into python."This is intentional :-) Basically, I need something that is close enough to the C macros. Imagine a C function with a "bit field" argument, that you want to call via `ctypes`. Then it's nice to have some symbols to `or` them instead of numbers.
ht
@ht: you must mean bitwise or that is `|` in Python. Notice that sets and bitflags behave the same with the `|` operator -- so in Python you might implement those combining flags as either ints or sets if you like.
kaizer.se
You are right, I meant `|`.
ht
+3  A: 

In the same spirit as Kugel, but noticing that collections.namedtuple is very similar.. it is a tuple, thus immutable, and it has field names. Namedtuple was introduced in Python 2.6.

Here is how you might use namedtuple:

import collections

def make_constants(variables):
    n = collections.namedtuple('Constants', variables.keys())
    return n(**variables)

c = make_constants({"a": 2, "b": 76})
print c
# the output is:
# Constants(a=2, b=76)
kaizer.se
+1  A: 

I think a common idiom is

class numericConstant:
    One = 1
    Two = 2

#usage
print (numericConstant.One + numericConstant.Two)

The drawback is that it doesn't prevent someone overwriting the "constant" values, i.e.

  numericConstant.One = 7  #oops...

but in keeping with Python's "consenting adults" philosophy, why prevent in a forceful way something you wouldn't want to do in the first place?...

mjv
+1  A: 

Your solution seems rather over-engineered. Just make a module and throw in your constants with capital letters. We are all adults...

#myconstants.py

ONE = 1
TWO = 2
THREE = 3
truppo