How do I create a constant in Python?

后端 未结 30 3195
既然无缘
既然无缘 2020-11-22 09:07

Is there a way to declare a constant in Python? In Java we can create constant values in this manner:

public static          


        
30条回答
  •  甜味超标
    2020-11-22 09:22

    Unfortunately the Python has no constants so yet and it is shame. ES6 already added support constants to JavaScript (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const) since it is a very useful thing in any programming language. As answered in other answers in Python community use the convention - user uppercase variable as constants, but it does not protect against arbitrary errors in code. If you like, you may be found useful a single-file solution as next (see docstrings how use it).

    file constants.py

    import collections
    
    
    __all__ = ('const', )
    
    
    class Constant(object):
        """
        Implementation strict constants in Python 3.
    
        A constant can be set up, but can not be changed or deleted.
        Value of constant may any immutable type, as well as list or set.
        Besides if value of a constant is list or set, it will be converted in an immutable type as next:
            list -> tuple
            set -> frozenset
        Dict as value of a constant has no support.
    
        >>> const = Constant()
        >>> del const.temp
        Traceback (most recent call last):
        NameError: name 'temp' is not defined
        >>> const.temp = 1
        >>> const.temp = 88
        Traceback (most recent call last):
            ...
        TypeError: Constanst can not be changed
        >>> del const.temp
        Traceback (most recent call last):
            ...
        TypeError: Constanst can not be deleted
        >>> const.I = ['a', 1, 1.2]
        >>> print(const.I)
        ('a', 1, 1.2)
        >>> const.F = {1.2}
        >>> print(const.F)
        frozenset([1.2])
        >>> const.D = dict()
        Traceback (most recent call last):
            ...
        TypeError: dict can not be used as constant
        >>> del const.UNDEFINED
        Traceback (most recent call last):
            ...
        NameError: name 'UNDEFINED' is not defined
        >>> const()
        {'I': ('a', 1, 1.2), 'temp': 1, 'F': frozenset([1.2])}
        """
    
        def __setattr__(self, name, value):
            """Declaration a constant with value. If mutable - it will be converted to immutable, if possible.
            If the constant already exists, then made prevent againt change it."""
    
            if name in self.__dict__:
                raise TypeError('Constanst can not be changed')
    
            if not isinstance(value, collections.Hashable):
                if isinstance(value, list):
                    value = tuple(value)
                elif isinstance(value, set):
                    value = frozenset(value)
                elif isinstance(value, dict):
                    raise TypeError('dict can not be used as constant')
                else:
                    raise ValueError('Muttable or custom type is not supported')
            self.__dict__[name] = value
    
        def __delattr__(self, name):
            """Deny against deleting a declared constant."""
    
            if name in self.__dict__:
                raise TypeError('Constanst can not be deleted')
            raise NameError("name '%s' is not defined" % name)
    
        def __call__(self):
            """Return all constans."""
    
            return self.__dict__
    
    
    const = Constant()
    
    
    if __name__ == '__main__':
        import doctest
        doctest.testmod()
    

    If this is not enough, see full testcase for it.

    import decimal
    import uuid
    import datetime
    import unittest
    
    from ..constants import Constant
    
    
    class TestConstant(unittest.TestCase):
        """
        Test for implementation constants in the Python
        """
    
        def setUp(self):
    
            self.const = Constant()
    
        def tearDown(self):
    
            del self.const
    
        def test_create_constant_with_different_variants_of_name(self):
    
            self.const.CONSTANT = 1
            self.assertEqual(self.const.CONSTANT, 1)
            self.const.Constant = 2
            self.assertEqual(self.const.Constant, 2)
            self.const.ConStAnT = 3
            self.assertEqual(self.const.ConStAnT, 3)
            self.const.constant = 4
            self.assertEqual(self.const.constant, 4)
            self.const.co_ns_ta_nt = 5
            self.assertEqual(self.const.co_ns_ta_nt, 5)
            self.const.constant1111 = 6
            self.assertEqual(self.const.constant1111, 6)
    
        def test_create_and_change_integer_constant(self):
    
            self.const.INT = 1234
            self.assertEqual(self.const.INT, 1234)
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.INT = .211
    
        def test_create_and_change_float_constant(self):
    
            self.const.FLOAT = .1234
            self.assertEqual(self.const.FLOAT, .1234)
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.FLOAT = .211
    
        def test_create_and_change_list_constant_but_saved_as_tuple(self):
    
            self.const.LIST = [1, .2, None, True, datetime.date.today(), [], {}]
            self.assertEqual(self.const.LIST, (1, .2, None, True, datetime.date.today(), [], {}))
    
            self.assertTrue(isinstance(self.const.LIST, tuple))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.LIST = .211
    
        def test_create_and_change_none_constant(self):
    
            self.const.NONE = None
            self.assertEqual(self.const.NONE, None)
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.NONE = .211
    
        def test_create_and_change_boolean_constant(self):
    
            self.const.BOOLEAN = True
            self.assertEqual(self.const.BOOLEAN, True)
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.BOOLEAN = False
    
        def test_create_and_change_string_constant(self):
    
            self.const.STRING = "Text"
            self.assertEqual(self.const.STRING, "Text")
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.STRING += '...'
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.STRING = 'TEst1'
    
        def test_create_dict_constant(self):
    
            with self.assertRaisesRegexp(TypeError, 'dict can not be used as constant'):
                self.const.DICT = {}
    
        def test_create_and_change_tuple_constant(self):
    
            self.const.TUPLE = (1, .2, None, True, datetime.date.today(), [], {})
            self.assertEqual(self.const.TUPLE, (1, .2, None, True, datetime.date.today(), [], {}))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.TUPLE = 'TEst1'
    
        def test_create_and_change_set_constant(self):
    
            self.const.SET = {1, .2, None, True, datetime.date.today()}
            self.assertEqual(self.const.SET, {1, .2, None, True, datetime.date.today()})
    
            self.assertTrue(isinstance(self.const.SET, frozenset))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.SET = 3212
    
        def test_create_and_change_frozenset_constant(self):
    
            self.const.FROZENSET = frozenset({1, .2, None, True, datetime.date.today()})
            self.assertEqual(self.const.FROZENSET, frozenset({1, .2, None, True, datetime.date.today()}))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.FROZENSET = True
    
        def test_create_and_change_date_constant(self):
    
            self.const.DATE = datetime.date(1111, 11, 11)
            self.assertEqual(self.const.DATE, datetime.date(1111, 11, 11))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.DATE = True
    
        def test_create_and_change_datetime_constant(self):
    
            self.const.DATETIME = datetime.datetime(2000, 10, 10, 10, 10)
            self.assertEqual(self.const.DATETIME, datetime.datetime(2000, 10, 10, 10, 10))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.DATETIME = None
    
        def test_create_and_change_decimal_constant(self):
    
            self.const.DECIMAL = decimal.Decimal(13123.12312312321)
            self.assertEqual(self.const.DECIMAL, decimal.Decimal(13123.12312312321))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.DECIMAL = None
    
        def test_create_and_change_timedelta_constant(self):
    
            self.const.TIMEDELTA = datetime.timedelta(days=45)
            self.assertEqual(self.const.TIMEDELTA, datetime.timedelta(days=45))
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.TIMEDELTA = 1
    
        def test_create_and_change_uuid_constant(self):
    
            value = uuid.uuid4()
            self.const.UUID = value
            self.assertEqual(self.const.UUID, value)
    
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be changed'):
                self.const.UUID = []
    
        def test_try_delete_defined_const(self):
    
            self.const.VERSION = '0.0.1'
            with self.assertRaisesRegexp(TypeError, 'Constanst can not be deleted'):
                del self.const.VERSION
    
        def test_try_delete_undefined_const(self):
    
            with self.assertRaisesRegexp(NameError, "name 'UNDEFINED' is not defined"):
                del self.const.UNDEFINED
    
        def test_get_all_defined_constants(self):
    
            self.assertDictEqual(self.const(), {})
    
            self.const.A = 1
            self.assertDictEqual(self.const(), {'A': 1})
    
            self.const.B = "Text"
            self.assertDictEqual(self.const(), {'A': 1, 'B': "Text"})
    

    Advantages: 1. Access to all constants for whole project 2. Strict control for values of constants

    Lacks: 1. Not support for custom types and the type 'dict'

    Notes:

    1. Tested with Python3.4 and Python3.5 (I am use the 'tox' for it)

    2. Testing environment:

    .

    $ uname -a
    Linux wlysenko-Aspire 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
    

提交回复
热议问题