Welcome, guest | Sign In | My Account | Store | Cart

This is a variation on the existing recipe "Constants in Python" by Alex Martelli. It binds a variable to the type value at first usage. Further usage is then restricted to values of the same type. This avoids a variable of, say, type string to be re-used to contain an integer.

Python, 40 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
"""
Constant types in Python.
"""
__doc__ = """
This is a variation on "Constants in Python" by Alex Martelli, from which the
solution idea was borrowed, and enhanced according suggestions of Zoran Isailovski.

In Python, any variable can be re-bound at will -- and modules don't let you
define special methods such as an instance's __setattr__ to stop attribute
re-binding. Easy solution (in Python 2.1 and up): use an instance as "module"...

In Python 2.1 and up, no check is made any more to force entries in sys.modules
to be actually module objects. You can install an instance object there and take
advantage of its attribute-access special methods (e.g., as in this snippet, to
prevent type rebindings. 

Usage:
  import consttype
  consttype.magic = 23    # Bind an attribute to a type ONCE
  consttype.magic = 88    # Re-bind it to a same type again
  consttype.magic = "one" # But NOT re-bind it to another type: this raises consttype._ConstError
  del consttype.magic     # Remove an named attribute
  consttype.__del__()     # Remove all attributes
"""

class _consttype:
    class _ConstTypeError(TypeError):
        pass
    def __repr__(self):
        return "Constant type definitions."
    def __setattr__(self, name, value):
        v = self.__dict__.get(name, value)
        if type(v) is not type(value):
            raise self._ConstTypeError, "Can't rebind %s to %s" % (type(v), type(value))
        self.__dict__[name] = value
    def __del__(self):
        self.__dict__.clear()

import sys
sys.modules[__name__] = _consttype()

I liked the constant idea as suggested by Alex, and wondered whether I could use this to implement it for a strong type checking mechanism ala Modula-2, which I used a lot in the past. To my amazement, it was simpler then I thought. But, as always, improvements are welcome.

2 comments

Zoran Isailovski 18 years, 11 months ago  # | flag

I like this one. Just a vew hints ... * You don't need all those parentheses

  • The "<>" operator is depricated in favor of "!="

  • Better yet, use "is not"

  • Save one dict lookup by not checking has_key

    def __setattr__(self, name, value): v = self.__dict__.get(name, value) if type(v) is not type(value): raise self._ConstError, "Can't rebind %s to %s" % (type(v), type(value)) self.__dict__[name] = value

I'm not sure if sys.modules[__name__] = _consttype() is a good idea, since reload does require a module, even if import doesn't.

Ruud Erwig (author) 18 years, 11 months ago  # | flag

Thanks for the suggestions Zoran, they definitive improve the code. For the moment sys.modules[__name__] seems to work. Perhaps there is somebody to shed some light on this issue.

Created by Ruud Erwig on Fri, 13 May 2005 (PSF)
Python recipes (4591)
Ruud Erwig's recipes (1)

Required Modules

Other Information and Tasks