How do I create a constant in Python?

后端 未结 30 2549
既然无缘
既然无缘 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:19

    In Python instead of language enforcing something, people use naming conventions e.g __method for private methods and using _method for protected methods.

    So in same manner you can simply declare the constant as all caps e.g.

    MY_CONSTANT = "one"
    

    If you want that this constant never changes, you can hook into attribute access and do tricks, but a simpler approach is to declare a function

    def MY_CONSTANT():
        return "one"
    

    Only problem is everywhere you will have to do MY_CONSTANT(), but again MY_CONSTANT = "one" is the correct way in python(usually).

    You can also use namedtuple to create constants:

    >>> from collections import namedtuple
    >>> Constants = namedtuple('Constants', ['pi', 'e'])
    >>> constants = Constants(3.14, 2.718)
    >>> constants.pi
    3.14
    >>> constants.pi = 3
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: can't set attribute
    
    0 讨论(0)
  • 2020-11-22 09:19

    In python, a constant is simply a variable with a name in all capitals, with words separated by the underscore character,

    e.g

    DAYS_IN_WEEK = 7

    The value is mutable, as in you can change it. But given the rules for the name tell you is a constant, why would you? I mean, it is your program after all!

    This is the approach taken throughout python. There is no private keyword for the same reason. Prefix the name with an underscore and you know it is intended to be private. Code can break the rule....just as a programmer could remove the private keyword anyway.

    Python could have added a const keyword... but a programmer could remove keyword and then change the constant if they want to, but why do that? If you want to break the rule, you could change the rule anyway. But why bother to break the rule if the name makes the intention clear?

    Maybe there is some unit test where it makes sense to apply a change to value? To see what happens for an 8 day week even though in the real world the number of days in the week cannot be changed. If the language stopped you making an exception if there is just this one case you need to break the rule...you would then have to stop declaring it as a constant, even though it still is a constant in the application, and there is just this one test case that sees what happens if it is changed.

    The all upper case name tells you it is intended to be a constant. That is what is important. Not a language forcing constraints on code you have the power to change anyway.

    That is the philosophy of python.

    0 讨论(0)
  • 2020-11-22 09:20

    Properties are one way to create constants. You can do it by declaring a getter property, but ignoring the setter. For example:

    class MyFinalProperty(object):
    
        @property
        def name(self):
            return "John"
    

    You can have a look at an article I've written to find more ways to use Python properties.

    0 讨论(0)
  • 2020-11-22 09:21

    We can create a descriptor object.

    class Constant:
      def __init__(self,value=None):
        self.value = value
      def __get__(self,instance,owner):
        return self.value
      def __set__(self,instance,value):
        raise ValueError("You can't change a constant")
    

    1) If we wanted to work with constants at the instance level then:

    class A:
      NULL = Constant()
      NUM = Constant(0xFF)
    
    class B:
      NAME = Constant('bar')
      LISTA = Constant([0,1,'INFINITY'])
    
    >>> obj=A()
    >>> print(obj.NUM)  #=> 255
    >>> obj.NUM =100
    
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    ValueError: You can't change a constant
    

    2) if we wanted to create constants only at the class level, we could use a metaclass that serves as a container for our constants (our descriptor objects); all the classes that descend will inherit our constants (our descriptor objects) without any risk that can be modified.

    # metaclass of my class Foo
    class FooMeta(type): pass
    
    # class Foo
    class Foo(metaclass=FooMeta): pass
    
    # I create constants in my metaclass
    FooMeta.NUM = Constant(0xff)
    FooMeta.NAME = Constant('FOO')
    
    >>> Foo.NUM   #=> 255
    >>> Foo.NAME  #=> 'FOO'
    >>> Foo.NUM = 0 #=> ValueError: You can't change a constant
    

    If I create a subclass of Foo, this class will inherit the constant without the possibility of modifying them

    class Bar(Foo): pass
    
    >>> Bar.NUM  #=> 255
    >>> Bar.NUM = 0  #=> ValueError: You can't change a constant
    
    0 讨论(0)
  • 2020-11-22 09:21

    I am trying different ways to create a real constant in Python and perhaps I found the pretty solution.

    Example:

    Create container for constants

    >>> DAYS = Constants(
    ...     MON=0,
    ...     TUE=1,
    ...     WED=2,
    ...     THU=3,
    ...     FRI=4,
    ...     SAT=5,
    ...     SUN=6
    ... )   
    

    Get value from container

    >>> DAYS.MON
    0
    >>> DAYS['MON']
    0  
    

    Represent with pure python data structures

    >>> list(DAYS)
    ['WED', 'SUN', 'FRI', 'THU', 'MON', 'TUE', 'SAT']
    >>> dict(DAYS)
    {'WED': 2, 'SUN': 6, 'FRI': 4, 'THU': 3, 'MON': 0, 'TUE': 1, 'SAT': 5}
    

    All constants are immutable

    >>> DAYS.MON = 7
    ...
    AttributeError: Immutable attribute
    
    >>> del DAYS.MON 
    ...
    AttributeError: Immutable attribute
    

    Autocomplete only for constants

    >>> dir(DAYS)
    ['FRI', 'MON', 'SAT', 'SUN', 'THU', 'TUE', 'WED']
    

    Sorting like list.sort

    >>> DAYS.sort(key=lambda (k, v): v, reverse=True)
    >>> list(DAYS)
    ['SUN', 'SAT', 'FRI', 'THU', 'WED', 'TUE', 'MON']
    

    Copability with python2 and python3

    Simple container for constants

    from collections import OrderedDict
    from copy import deepcopy
    
    class Constants(object):
        """Container of constant"""
    
        __slots__ = ('__dict__')
    
        def __init__(self, **kwargs):
    
            if list(filter(lambda x: not x.isupper(), kwargs)):
                raise AttributeError('Constant name should be uppercase.')
    
            super(Constants, self).__setattr__(
                '__dict__',
                OrderedDict(map(lambda x: (x[0], deepcopy(x[1])), kwargs.items()))
            )
    
        def sort(self, key=None, reverse=False):
            super(Constants, self).__setattr__(
                '__dict__',
                OrderedDict(sorted(self.__dict__.items(), key=key, reverse=reverse))
            )
    
        def __getitem__(self, name):
            return self.__dict__[name]
    
        def __len__(self):
            return  len(self.__dict__)
    
        def __iter__(self):
            for name in self.__dict__:
                yield name
    
        def keys(self):
            return list(self)
    
        def __str__(self):
            return str(list(self))
    
        def __repr__(self):
            return '<%s: %s>' % (self.__class__.__name__, str(self.__dict__))
    
        def __dir__(self):
            return list(self)
    
        def __setattr__(self, name, value):
            raise AttributeError("Immutable attribute")
    
        def __delattr__(*_):
            raise AttributeError("Immutable attribute")
    
    
    0 讨论(0)
  • 2020-11-22 09:22

    No there is not. You cannot declare a variable or value as constant in Python. Just don't change it.

    If you are in a class, the equivalent would be:

    class Foo(object):
        CONST_NAME = "Name"
    

    if not, it is just

    CONST_NAME = "Name"
    

    But you might want to have a look at the code snippet Constants in Python by Alex Martelli.


    As of Python 3.8, there's a typing.Final variable annotation that will tell static type checkers (like mypy) that your variable shouldn't be reassigned. This is the closest equivalent to Java's final. However, it does not actually prevent reassignment:

    from typing import Final
    
    a: Final = 1
    
    # Executes fine, but mypy will report an error if you run mypy on this:
    a = 2
    
    0 讨论(0)
提交回复
热议问题