# Symbolic Constants

## Overview

It is often useful to define names which will be treated as constants. `twisted.python.constants` provides APIs for defining such symbolic constants with minimal overhead and some useful features beyond those afforded by the common Python idioms for this task.

This document will explain how to use these APIs and what circumstances they might be helpful in.

## Constant Names

Constants which have no value apart from their name and identity can be defined by subclassing `Names`. Consider this example, in which some HTTP request method constants are defined.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from twisted.python.constants import NamedConstant, Names
    class METHOD(Names):
        """
        Constants representing various HTTP request methods.
        """
        GET = NamedConstant()
        PUT = NamedConstant()
        POST = NamedConstant()
        DELETE = NamedConstant()

Only direct subclasses of `Names` are supported (i.e., you cannot subclass `METHOD` to add new constants the collection).

Given this definition, constants can be looked up by name using attribute access on the `METHOD` object:

    >>> METHOD.GET
    <METHOD=GET>
    >>> METHOD.PUT
    <METHOD=PUT>
    >>>

If it's necessary to look up constants based on user input of some sort, a safe way to do it is using `lookupByName`:

    >>> METHOD.lookupByName('GET')
    <METHOD=GET>
    >>> METHOD.lookupByName('__doc__')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "twisted/python/constants.py", line 145, in lookupByName
        raise ValueError(name)
    ValueError: __doc__
    >>>

As demonstrated, it is safe because any name not associated with a constant (even those special names initialized by Python itself) will result in `ValueError` being raised, not some other object not intended to be used the way the constants are used.

The constants can also be enumerated using the `iterconstants` method.

    >>> list(METHOD.iterconstants())
    [<METHOD=GET>, <METHOD=PUT>, <METHOD=POST>, <METHOD=DELETE>]

And constants can also be compared, either for equality or identity:

    >>> METHOD.GET is METHOD.GET
    True
    >>> METHOD.GET == METHOD.GET
    True
    >>> METHOD.GET is METHOD.PUT
    False
    >>> METHOD.GET == METHOD.PUT
    False
    >>>

Custom functionality can also be associated with constants defined this way. A subclass of `Names` may define class methods to implement such functionality. Consider this redefinition of `METHOD`:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    from twisted.python.constants import NamedConstant, Names
    class METHOD(Names):
        """
        Constants representing various HTTP request methods.
        """
        GET = NamedConstant()
        PUT = NamedConstant()
        POST = NamedConstant()
        DELETE = NamedConstant()

        @classmethod
        def isIdempotent(cls, method):
            """
            Return True if the given method is side-effect free, False otherwise.
            """
            return method is cls.GET

This functionality can be used as any class methods are used:

    >>> METHOD.isIdempotent(METHOD.GET)
    True
    >>> METHOD.isIdempotent(METHOD.POST)
    False
    >>>

## Constants With Values

Constants with a particular associated value are supported by the `Values` base class. Consider this example, in which some HTTP status code constants are defined.

    1
    2
    3
    4
    5
    6
    7
    8
    from twisted.python.constants import ValueConstant, Values
    class STATUS(Values):
        """
        Constants representing various HTTP status codes.
        """
        OK = ValueConstant("200")
        FOUND = ValueConstant("302")
        NOT_FOUND = ValueConstant("404")

As with `Names`, constants are accessed as attributes of the class object:

    >>> STATUS.OK
    <STATUS=OK>
    >>> STATUS.FOUND
    <STATUS=FOUND>
    >>>

Additionally, the values of the constants can be accessed using the `value` attribute of one these objects:

    >>> STATUS.OK.value
    '200'
    >>>

And as with `Names`, constants can be looked up by name:

    >>> STATUS.lookupByName('NOT_FOUND')
    <STATUS=NOT_FOUND>
    >>>

Constants on a `Values` subclass can also be looked up by value:

    >>> STATUS.lookupByValue('404')
    <STATUS=NOT_FOUND>
    >>> STATUS.lookupByValue('500')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "twisted/python/constants.py", line 244, in lookupByValue
          raise ValueError(value)
    ValueError: 500
    >>>

Multiple constants may have the same value. If they do, `lookupByValue` will find the one which is defined first.

Iteration is also supported:

    >>> list(STATUS.iterconstants())
    [<STATUS=OK>, <STATUS=FOUND>, <STATUS=NOT_FOUND>]
    >>>

And constants can be compared for equality and identity:

    >>> STATUS.OK == STATUS.OK
    True
    >>> STATUS.OK is STATUS.OK
    True
    >>> STATUS.OK == STATUS.OK
    True
    >>> STATUS.OK is STATUS.NOT_FOUND
    False
    >>> STATUS.OK == STATUS.NOT_FOUND
    False
    >>>

And, as with `Names`, a subclass of `Values` can define methods:

    from twisted.python.constants import ValueConstant, Values
    class STATUS(Values):
        """
        Constants representing various HTTP status codes.
        """
        OK = ValueConstant("200")
        NO_CONTENT = ValueConstant("204")
        NOT_MODIFIED = ValueConstant("304")
        NOT_FOUND = ValueConstant("404")

        @classmethod
        def hasBody(cls, status):
            """
            Return True if the given status is associated with a response body,
            False otherwise.
            """
            return status in (cls.NO_CONTENT, cls.NOT_MODIFIED)

This functionality can be used as any class methods are used:

    >>> STATUS.hasBody(STATUS.OK)
    True
    >>> STATUS.hasBody(STATUS.NO_CONTENT)
    False
    >>>

Index

Version: 12.0.0