Jak utworzyć stałą w Pythonie?

Czy jest sposób na zadeklarowanie stałej w Pythonie? W Javie możemy tworzyć wartości stałe w ten sposób:

public static final String CONST_NAME = "Name";

Jaki jest odpowiednik powyższej deklaracji stałej Javy w Pythonie?

Author: Steven Vascellaro, 0000-00-00

30 answers

Nie ma. W Pythonie Nie Można zadeklarować zmiennej ani wartości jako stałej. Tylko tego nie zmieniaj.

Jeśli jesteś w klasie, odpowiednikiem będzie:

class Foo(object):
    CONST_NAME = "Name"

Jeśli nie, to po prostu

CONST_NAME = "Name"

Ale warto przyjrzeć się fragmentowi kodu stałe w Pythonie autorstwa Alexa Martelli.

 742
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-30 21:16:38

Nie ma słowa kluczowego const jak w innych językach, jednak możliwe jest utworzenie właściwości, która ma "funkcję getter" do odczytu danych, ale nie ma "funkcji setter" do ponownego zapisu danych. to zasadniczo chroni identyfikator przed zmianą.

Oto alternatywna implementacja używająca właściwości klasy:

zauważ, że kod nie jest łatwy dla czytelnika zastanawiającego się nad stałymi. Zobacz Wyjaśnienie poniżej

def constant(f):
    def fset(self, value):
        raise TypeError
    def fget(self):
        return f()
    return property(fget, fset)

class _Const(object):
    @constant
    def FOO():
        return 0xBAADFACE
    @constant
    def BAR():
        return 0xDEADBEEF

CONST = _Const()

print CONST.FOO
##3131964110

CONST.FOO = 0
##Traceback (most recent call last):
##    ...
##    CONST.FOO = 0
##TypeError: None

Wyjaśnienie Kodu:

  1. Zdefiniuj funkcję constant, która pobiera wyrażenie i używa go do skonstruowania "gettera" - funkcji, która zwraca wyłącznie wartość wyrażenia.
  2. funkcja setter podnosi TypeError, więc jest tylko do odczytu
  3. Użyj funkcji constant, którą właśnie stworzyliśmy jako dekorację, aby szybko zdefiniować właściwości tylko do odczytu.

I w inny bardziej staromodny sposób:

(na kod jest dość skomplikowany, więcej wyjaśnień poniżej)

class _Const(object):
    @apply
    def FOO():
        def fset(self, value):
            raise TypeError
        def fget(self):
            return 0xBAADFACE
        return property(**locals())

CONST = _Const()

print CONST.FOO
##3131964110

CONST.FOO = 0
##Traceback (most recent call last):
##    ...
##    CONST.FOO = 0
##TypeError: None

zwróć uwagę, że dekorator @ apply wydaje się przestarzały.

  1. aby zdefiniować identyfikator FOO, Firs definiuje dwie funkcje (fset, fget - nazwy są do wyboru).
  2. następnie użyj wbudowanej funkcji property, aby zbudować obiekt, który może być " set " lub "get".
  3. Uwaga: dwa pierwsze parametry funkcji property są nazwane fset i fget.
  4. użyj faktu, że wybraliśmy te w tym celu należy utworzyć słownik słów kluczowych, używając ** (podwójnej gwiazdki) zastosowanej do wszystkich lokalnych definicji tego zakresu, aby przekazać parametry do funkcji property
 298
Author: inv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-06 08:23:17

W Pythonie zamiast wymuszania czegoś, ludzie używają konwencji nazewnictwa, np. __method dla metod prywatnych i _method dla metod chronionych.

Więc w ten sam sposób można po prostu zadeklarować stałą jako wszystkie caps np.

MY_CONSTANT = "one"

Jeśli chcesz, aby ta stała nigdy się nie zmieniała, możesz podłączyć się do dostępu do atrybutów i wykonywać sztuczki, ale prostszym podejściem jest zadeklarowanie funkcji

def MY_CONSTANT():
    return "one"

Jedynym problemem jest to, że wszędzie będziesz musiał wykonać MY_CONSTANT (), ale znowu MY_CONSTANT = "one" jest poprawny sposób w Pythonie (Zwykle).

Możesz również użyć namedtuple do utworzenia stałych:

>>> 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
 83
Author: Anurag Uniyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-02 19:46:01

Prawdopodobnie brakuje mi tutaj sztuczki, ale to chyba działa na mnie:

class CONST(object):
    FOO = 1234

    def __setattr__(self, *_):
        pass

CONST = CONST()

#----------

print CONST.FOO    # 1234

CONST.FOO = 4321
CONST.BAR = 5678

print CONST.FOO    # Still 1234!
print CONST.BAR    # Oops AttributeError

Utworzenie instancji pozwala magicznej metodzie __setattr__ rozpocząć i przechwycić próby ustawienia zmiennej FOO. Możesz tu zrobić wyjątek, jeśli chcesz. Utworzenie instancji instancji nad nazwą klasy uniemożliwia dostęp bezpośrednio przez klasę.

To całkowity ból dla jednej wartości, ale możesz przywiązać wiele do swojego CONST obiektu. Posiadanie wyższej klasy, nazwa klasy również wydaje się nieco groteskowa, ale Myślę, że to dość zwięzłe.

 33
Author: Jon Betts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-24 16:17:58

Jak zapewne już wiesz, Python nie ma stałych: (

Być może najprostszą alternatywą jest zdefiniowanie dla niej funkcji. Np.

def MY_CONSTANT():
    return 42

MY_CONSTANT() teraz ma całą funkcjonalność stałej (plus kilka irytujących szelek).

 16
Author: Saeed Baig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-14 23:00:35

Oprócz dwóch głównych odpowiedzi (wystarczy użyć zmiennych z wielkimi nazwami lub użyć właściwości, aby wartości były tylko do odczytu), chcę wspomnieć, że możliwe jest użycie metaklasy w celu zaimplementowania stałych o nazwie. Podaję bardzo proste rozwiązanie przy użyciu metaklasy na GitHub, które może być pomocne, jeśli chcesz, aby wartości były bardziej informujące o ich typie/nazwie:

>>> from named_constants import Constants
>>> class Colors(Constants):
...     black = 0
...     red = 1
...     white = 15
...
>>> c = Colors.black
>>> c == 0
True
>>> c
Colors.black
>>> c.name()
'black'
>>> Colors(0) is c
True

Jest to nieco bardziej zaawansowany Python, ale nadal bardzo łatwy w użyciu i poręczny. (Moduł posiada kilka innych funkcji, w tym stałe tylko do odczytu, patrz jego README.)

Istnieją podobne rozwiązania unoszące się w różnych repozytoriach, ale według mojej najlepszej wiedzy albo brakuje im jednej z podstawowych cech, których oczekiwałbym od stałych (takich jak bycie stałymi lub bycie dowolnego typu), albo dodano Ezoteryczne cechy, które czynią je mniej ogólnymi. Ale YMMV, byłbym wdzięczny za opinie. :-)

 15
Author: hans_meine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-10 21:25:47

Edit: Dodano przykładowy kod dla Pythona 3

Uwaga: ta druga odpowiedź wygląda na to, że zapewnia znacznie bardziej kompletną implementację podobną do poniższej (z większą liczbą funkcji).

Najpierw stwórz metaklasę :

class MetaConst(type):
    def __getattr__(cls, key):
        return cls[key]

    def __setattr__(cls, key, value):
        raise TypeError

Zapobiega to zmianie właściwości statycznych. Następnie stwórz inną klasę, która używa tej metaklasy:

class Const(object):
    __metaclass__ = MetaConst

    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        raise TypeError

Lub, jeśli używasz Pythona 3:

class Const(object, metaclass=MetaConst):
    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        raise TypeError

Powinno to zapobiec zmianie właściwości instancji. Aby go używać, dziedziczenie:

class MyConst(Const):
    A = 1
    B = 2

Teraz rekwizyty, dostępne bezpośrednio lub za pośrednictwem instancji, powinny być stałe:

MyConst.A
# 1
my_const = MyConst()
my_const.A
# 1

MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError

Oto przykład powyżej w akcji. oto kolejny przykład Pythona 3.

 12
Author: doubleswirve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:28

Oto Implementacja klasy "Constants", która tworzy instancje z atrybutami tylko do odczytu (stałymi). Na przykład może użyć Nums.PI, Aby uzyskać wartość, która została zainicjalizowana jako 3.14159, a Nums.PI = 22 podnosi wyjątek.

# ---------- Constants.py ----------
class Constants(object):
    """
    Create objects with read-only (constant) attributes.
    Example:
        Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
        print 10 + Nums.PI
        print '----- Following line is deliberate ValueError -----'
        Nums.PI = 22
    """

    def __init__(self, *args, **kwargs):
        self._d = dict(*args, **kwargs)

    def __iter__(self):
        return iter(self._d)

    def __len__(self):
        return len(self._d)

    # NOTE: This is only called if self lacks the attribute.
    # So it does not interfere with get of 'self._d', etc.
    def __getattr__(self, name):
        return self._d[name]

    # ASSUMES '_..' attribute is OK to set. Need this to initialize 'self._d', etc.
    #If use as keys, they won't be constant.
    def __setattr__(self, name, value):
        if (name[0] == '_'):
            super(Constants, self).__setattr__(name, value)
        else:
            raise ValueError("setattr while locked", self)

if (__name__ == "__main__"):
    # Usage example.
    Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
    print 10 + Nums.PI
    print '----- Following line is deliberate ValueError -----'
    Nums.PI = 22

Dzięki @MikeGraham 's FrozenDict , który wykorzystałem jako punkt wyjścia. Zmieniono, więc zamiast Nums['ONE'] składnia użycia to Nums.ONE.

I dzięki odpowiedzi @Raufio, za pomysł nadpisania _ _ setattr__.

Lub do realizacji z więcej funkcjonalności, patrz @ Hans_meine ' s named_constants at GitHub

 6
Author: ToolmakerSteve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:30

Właściwości są jednym ze sposobów tworzenia stałych. Możesz to zrobić deklarując właściwość getter, ale ignorując setter. Na przykład:

class MyFinalProperty(object):

    @property
    def name(self):
        return "John"

Możesz rzucić okiem naartykuł, który napisałem , aby znaleźć więcej sposobów na korzystanie z właściwości Pythona.

 6
Author: nvd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-12 23:14:46

Stworzyłbym klasę, która nadpisuje metodę __setattr__ klasy obiektu bazowego i owinie moje stałe tym, zauważ, że używam Pythona 2.7:

class const(object):
    def __init__(self, val):
        super(const, self).__setattr__("value", val)
    def __setattr__(self, name, val):
        raise ValueError("Trying to change a constant value", self)

Aby zawinąć łańcuch:

>>> constObj = const("Try to change me")
>>> constObj.value
'Try to change me'
>>> constObj.value = "Changed"
Traceback (most recent call last):
   ...
ValueError: Trying to change a constant value
>>> constObj2 = const(" or not")
>>> mutableObj = constObj.value + constObj2.value
>>> mutableObj #just a string
'Try to change me or not'

To dość proste, ale jeśli chcesz używać stałych tak samo, jak nie - stały obiekt (bez użycia constObj.wartość), będzie nieco bardziej intensywny. Jest możliwe, że może to powodować problemy, więc najlepiej zachować .value, aby pokazać i wiedzieć, że robisz operacje ze stałymi (może nie najbardziej "pythonicznym" sposobem).

 4
Author: Raufio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-10 00:09:10

Niestety Python nie ma stałych więc jeszcze i szkoda. ES6 już dodał stałe wsparcia do JavaScript ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ), ponieważ jest to bardzo przydatna rzecz w każdym języku programowania. Podobnie jak w innych odpowiedziach w społeczności Pythona używa zmiennej convention-user jako stałych, ale nie chroni ona przed arbitralnymi błędami w kodzie. Jeśli chcesz, możesz okazać się przydatny pojedynczy plik rozwiązanie jako następne (zobacz docstrings jak go używać).

Plik 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()

Jeśli to nie wystarczy, Zobacz pełną walizkę testową.

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"})

Zalety: 1. Dostęp do wszystkich stałych dla całego projektu 2. Ścisła kontrola wartości stałych

Brak: 1. Nie obsługuje typów niestandardowych i typu "dict"

Uwagi:

  1. Testowane z Python3.4 i Python3. 5 (używam do tego 'toksykologii')

  2. Testowanie środowisko:

.

$ 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
 4
Author: Seti Volkylany,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-06 01:09:13

Pythoniczny sposób deklarowania "stałych" jest w zasadzie zmienną poziomu modułu:

RED = 1
GREEN = 2
BLUE = 3

A następnie napisz swoje klasy lub funkcje. Ponieważ stałe są prawie zawsze liczbami całkowitymi i są niezmienne w Pythonie, masz bardzo małe szanse na ich zmianę.

Chyba, że, oczywiście, jeśli jawnie ustawić RED = 2.

 3
Author: Xavier Ho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-21 13:28:28

Krotka technicznie kwalifikuje się jako stała, ponieważ krotka spowoduje błąd, jeśli spróbujesz zmienić jedną z jej wartości. Jeśli chcesz zadeklarować krotkę z jedną wartością, umieść przecinek po jej jedynej wartości, w ten sposób:

my_tuple = (0 """Or any other value""",)

Aby sprawdzić wartość tej zmiennej, użyj czegoś podobnego do tego:

if my_tuple[0] == 0:
    #Code goes here

Jeśli spróbujesz zmienić tę wartość, pojawi się błąd.

 3
Author: tobahhh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-09 21:51:12

Możesz użyć namedtuple jako obejścia, aby skutecznie utworzyć stałą, która działa tak samo jak statyczna zmienna końcowa w Javie ("stała"). Jak to obejść, to trochę eleganckie. (Bardziej eleganckim podejściem byłoby po prostu ulepszenie języka Python - - - jaki język pozwala na redefinicję math.pi? -- ale dygresję.)

(Jak to piszę, to zdaję sobie sprawę z innej odpowiedzi na to pytanie, ale będę kontynuował tutaj, ponieważ pokażę składnię, która bardziej przypomina to, czego można się spodziewać w Javie, ponieważ nie ma potrzeby tworzenia typu nazwanego , ponieważ namedtuple zmusza cię do tego.)

Idąc za twoim przykładem, pamiętaj, że w Javie musimy zdefiniować stałą wewnątrz jakiejś klasy ; ponieważ nie wspomniałeś nazwy klasy, nazwijmy ją Foo. Oto Klasa Java:

public class Foo {
  public static final String CONST_NAME = "Name";
}

Oto odpowiednik Pythona.

from collections import namedtuple
Foo = namedtuple('_Foo', 'CONST_NAME')('Name')

Kluczową kwestią, którą chcę tutaj dodać, jest to, że nie potrzebujesz oddzielnego typu Foo ("anonymous named tuple" byłoby miło, mimo że brzmi to jak oksymoron), więc nazwiemy nasz namedtuple _Foo, aby miejmy nadzieję, że nie ucieknie do importowania modułów.

Druga kwestia polega na tym, że natychmiast tworzymy instancję o nazwie, nazywając ją Foo; nie ma potrzeby robić tego w osobnym kroku (chyba że chcesz). Teraz możesz robić to, co potrafisz w Javie:

>>> Foo.CONST_NAME
'Name'

Ale nie można do niego przypisać:

>>> Foo.CONST_NAME = 'bar'
…
AttributeError: can't set attribute

Potwierdzenie: I myślałem, że wymyśliłem tak zwane podejście, ale potem widzę, że ktoś inny dał podobną (choć mniej zwartą) odpowiedź. Wtedy też zauważyłem Co to są "nazwane krotki" w Pythonie?, który wskazuje, że sys.version_info jest teraz nazwanyple, więc być może standardowa biblioteka Pythona wpadła na ten pomysł znacznie wcześniej.

Zauważ, że niestety (wciąż jest to Python), możesz wymazać całe Foo przypisanie razem:

>>> Foo = 'bar'

(facepalm)

Ale przynajmniej zapobiegamy zmianie wartości Foo.CONST_NAME, a to lepsze niż nic. Powodzenia.

 3
Author: Garret Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:47

Słowniki Pythona są mutowalne, więc nie wydają się dobrym sposobem na deklarowanie stałych:

>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}
 2
Author: n8boyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-30 07:36:28

W Pythonie stała jest po prostu zmienną z nazwą pisaną wielkimi literami, ze słowami oddzielonymi znakiem podkreślenia,

E. g

DAYS_IN_WEEK = 7

Wartość jest zmienna, ponieważ można ją zmienić. Ale biorąc pod uwagę zasady nazwy, powiedz ci jest stałą, dlaczego miałbyś to zrobić? To przecież Twój program!

Jest to podejście stosowane w Pythonie. Nie ma private słowa kluczowego z tego samego powodu. Przedrostek nazwy z podkreśleniem i wiesz o tym ma być prywatny. Kod może złamać zasadę....tak jak programista i tak mógłby usunąć prywatne słowo kluczowe.

Python mógł dodać słowo kluczowe const... ale programista może usunąć słowo kluczowe, a następnie zmienić stałą, jeśli chce, ale dlaczego to zrobić? Jeśli chcesz złamać zasadę, i tak możesz ją zmienić. Ale po co łamać regułę, jeśli nazwa jasno wyraża zamiar?

Może jest jakiś test jednostkowy, w którym sensowne jest zastosowanie zmiany do wartość? Aby zobaczyć, co się dzieje w 8-dniowym tygodniu, mimo że w realnym świecie liczba dni w tygodniu nie może być zmieniona. Jeśli język przestał robić wyjątek, jeśli jest tylko ten jeden przypadek, musisz złamać regułę...będziesz musiał przestać deklarować ją jako stałą, nawet jeśli nadal jest stałą w aplikacji, a jest tylko ten jeden przypadek testowy, który widzi, co się stanie, jeśli zostanie zmieniona.

Nazwa z wielkimi literami mówi, że ma być stała. To jest ważne. Nie język wymuszający ograniczenia na kodzie masz prawo do zmiany i tak.

To jest filozofia Pythona.
 2
Author: innov8,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-30 12:14:53

Po prostu Możesz:

STRING_CONSTANT = "hi"
NUMBER_CONSTANT = 89

Nadzieja, że wszystko będzie prostsze

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-06 09:15:39

W moim przypadku potrzebowałem immutable bytearrays do implementacji biblioteki kryptograficznej zawierającej wiele literalnych liczb, które chciałem zapewnić, że są stałe.

Ta odpowiedź działa, ale próba ponownego przypisania elementów bytearray nie powoduje błędu.

def const(func):
    '''implement const decorator'''
    def fset(self, val):
        '''attempting to set a const raises `ConstError`'''
        class ConstError(TypeError):
            '''special exception for const reassignment'''
            pass

        raise ConstError

    def fget(self):
        '''get a const'''
        return func()

    return property(fget, fset)


class Consts(object):
    '''contain all constants'''

    @const
    def C1():
        '''reassignment to C1 fails silently'''
        return bytearray.fromhex('deadbeef')

    @const
    def pi():
        '''is immutable'''
        return 3.141592653589793

Stałe są niezmienne, ale przypisanie stałej bytearray nie powiedzie się po cichu:

>>> c = Consts()
>>> c.pi = 6.283185307179586  # (https://en.wikipedia.org/wiki/Tau_(2%CF%80))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "consts.py", line 9, in fset
    raise ConstError
__main__.ConstError
>>> c.C1[0] = 0
>>> c.C1[0]
222
>>> c.C1
bytearray(b'\xde\xad\xbe\xef')

Potężniejsze, prostsze, a może nawet bardziej "pythoniczne" podejście wymaga użycia obiektów memoryview (bufor obiektów w

import sys

PY_VER = sys.version.split()[0].split('.')

if int(PY_VER[0]) == 2:
    if int(PY_VER[1]) < 6:
        raise NotImplementedError
    elif int(PY_VER[1]) == 6:
        memoryview = buffer

class ConstArray(object):
    '''represent a constant bytearray'''
    def __init__(self, init):
        '''
        create a hidden bytearray and expose a memoryview of that bytearray for
        read-only use
        '''
        if int(PY_VER[1]) == 6:
            self.__array = bytearray(init.decode('hex'))
        else:
            self.__array = bytearray.fromhex(init)

        self.array = memoryview(self.__array)

    def __str__(self):
        return str(self.__array)

    def __getitem__(self, *args, **kwargs):
       return self.array.__getitem__(*args, **kwargs)

Przypisanie elementu ConstArray jest TypeError:

>>> C1 = ConstArray('deadbeef')
>>> C1[0] = 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'ConstArray' object does not support item assignment
>>> C1[0]
222
 1
Author: jxqz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-25 16:37:03

Piszę util lib dla Pythona const: kkconst-pypi obsługa str, int, float, datetime

Instancja pola const zachowa zachowanie typu podstawowego.

Na przykład:

from __future__ import print_function
from kkconst import (
    BaseConst,
    ConstFloatField,
)

class MathConst(BaseConst):
    PI = ConstFloatField(3.1415926, verbose_name=u"Pi")
    E = ConstFloatField(2.7182818284, verbose_name=u"mathematical constant")  # Euler's number"
    GOLDEN_RATIO = ConstFloatField(0.6180339887, verbose_name=u"Golden Ratio")

magic_num = MathConst.GOLDEN_RATIO
assert isinstance(magic_num, ConstFloatField)
assert isinstance(magic_num, float)

print(magic_num)  # 0.6180339887
print(magic_num.verbose_name)  # Golden Ratio

Więcej Szczegółów użytkowania możesz przeczytać adres URL pypi: pypi lub github

 1
Author: kaka_ace,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-23 10:49:59

Możesz zawinąć stałą w tablicę numpy, oznaczyć ją tylko do zapisu i zawsze wywołać ją przez indeks zero.

import numpy as np

# declare a constant
CONSTANT = 'hello'

# put constant in numpy and make read only
CONSTANT = np.array([CONSTANT])
CONSTANT.flags.writeable = False
# alternatively: CONSTANT.setflags(write=0)

# call our constant using 0 index    
print 'CONSTANT %s' % CONSTANT[0]

# attempt to modify our constant with try/except
new_value = 'goodbye'
try:
    CONSTANT[0] = new_value
except:
    print "cannot change CONSTANT to '%s' it's value '%s' is immutable" % (
        new_value, CONSTANT[0])

# attempt to modify our constant producing ValueError
CONSTANT[0] = new_value



>>>
CONSTANT hello
cannot change CONSTANT to 'goodbye' it's value 'hello' is immutable
Traceback (most recent call last):
  File "shuffle_test.py", line 15, in <module>
    CONSTANT[0] = new_value
ValueError: assignment destination is read-only

Oczywiście chroni to tylko zawartość numpy, a nie samą zmienną "stałą"; nadal możesz to zrobić:

CONSTANT = 'foo'

I CONSTANT zmieniłyby się, jednak to szybko rzuciłoby TypeError, gdy po raz pierwszy CONSTANT[0] zostanie później wywołane w skrypcie.

Chociaż... Przypuszczam, że jeśli w pewnym momencie zmienisz go na
CONSTANT = [1,2,3]

Teraz nie dostaniesz TypeError już nie. hmmmm....

Https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.setflags.html

 1
Author: litepresence,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-01 04:25:37

Możemy utworzyć obiekt deskryptora:

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")

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
 1
Author: MVP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-12 15:57:09

Oto sztuczka, jeśli chcesz stałych i nie obchodzi ich wartości:

Po prostu zdefiniuj puste klasy.

Np:

class RED: 
    pass
class BLUE: 
    pass
 1
Author: Lym Zoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-11 07:03:36

Możesz użyć StringVar lub IntVar, itd, twoja stała jest const_val

val = 'Stackoverflow'
const_val = StringVar(val)
const.trace('w', reverse)

def reverse(*args):
    const_val.set(val)
 1
Author: Nqobizwe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-30 08:53:48

W Pythonie stałe nie istnieją. Możesz jednak wskazać, że zmienna jest stałą i nie może być zmieniana, dodając '_CONSTANT' na początku nazwy zmiennej, nazywając zmienną wielkimi literami i dodając komentarz za pomocą hashtagu (' # ') np. :

    normal_variable = 0
    CONSTANT_variable = 1    # This is a constant - do not change its value!   
 1
Author: Aryan Beezadhur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 20:03:45

Rozszerzając odpowiedź Raufio, dodaj repr , aby zwrócić wartość.

class const(object):
    def __init__(self, val):
        super(const, self).__setattr__("value", val)
    def __setattr__(self, name, val):
        raise ValueError("Trying to change a constant value", self)
    def __repr__(self):
        return ('{0}'.format(self.value))

dt = const(float(0.01))
print dt

Wtedy obiekt zachowuje się trochę bardziej jak można się spodziewać, można uzyskać do niego dostęp bezpośrednio niż '.wartość "

 0
Author: Jonathan Kimball Galloway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 15:10:23

Cóż.. mimo, że to nieaktualne, dodam tu moje 2 grosze: -)

class ConstDict(dict):
    def __init__(self, *args, **kwargs):
        super(ConstDict, self).__init__(*args, **kwargs)

    def __setitem__(self, key, value):
        if key in self:
            raise ValueError("Value %s already exists" % (key))
        super(ConstDict, self).__setitem__(key, value)

Zamiast ValueError do złamania, możesz zapobiec każdej aktualizacji. Zaletą tego jest to, że można dodawać stałe dynamicznie w programie, ale nie można zmienić po ustawieniu stałej. Możesz również dodać dowolną regułę lub cokolwiek przed ustawieniem stałej (coś jak key musi być łańcuchem znaków lub łańcuchem małych liter lub łańcuchem wielkich liter i tak dalej przed ustawieniem klucza)

Jednak ja nie widzę znaczenia ustawiania stałych w Pythonie. Żadna optymalizacja nie może się zdarzyć tak jak w C, a więc jest to coś, co nie jest wymagane, tak myślę.

 0
Author: thiruvenkadam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-20 13:03:28

Możesz emulować zmienne stałe za pomocą następnej klasy. Przykład użycia:

# Const
const = Const().add(two=2, three=3)

print 'const.two: ', const.two
print 'const.three: ', const.three

const.add(four=4)

print 'const.four: ', const.four

#const.four = 5 # a error here: four is a constant

const.add(six=6)

print 'const.six: ', const.six

const2 = Const().add(five=5) # creating a new namespace with Const()
print 'const2.five: ', const2.five
#print 'const2.four: ', const2.four # a error here: four does not exist in const2 namespace

const2.add(five=26)

Wywołaj konstruktor, gdy chcesz rozpocząć nową stałą przestrzeń nazw. Zauważ, że klasa jest pod ochroną przed nieoczekiwanymi modyfikacjami stałych typu sekwencji, gdy Klasa Martellego const nie jest.

Źródło znajduje się poniżej.
from copy import copy

class Const(object):
"A class to create objects with constant fields."

def __init__(self):
    object.__setattr__(self, '_names', [])


def add(self, **nameVals):
    for name, val in nameVals.iteritems():          
        if hasattr(self, name):
            raise ConstError('A field with a name \'%s\' is already exist in Const class.' % name)

        setattr(self, name, copy(val)) # set up getter

        self._names.append(name)

    return self


def __setattr__(self, name, val):
    if name in self._names:
        raise ConstError('You cannot change a value of a stored constant.')

    object.__setattr__(self, name, val)
 0
Author: sergzach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-27 16:36:11

Nie ma na to idealnego sposobu. Jak rozumiem, większość programistów będzie po prostu pisała identyfikator wielką literą, więc PI = 3.142 można łatwo zrozumieć jako stałą.

Z drugiej strony, jeśli chcesz czegoś, co działa jak stała, nie jestem pewien, czy to znajdziesz. Przy czymkolwiek zrobisz, zawsze będzie jakiś sposób edycji "stałej", więc tak naprawdę nie będzie to stała. Oto bardzo prosty, brudny przykład:
def define(name, value):
  if (name + str(id(name))) not in globals():
    globals()[name + str(id(name))] = value

def constant(name):
  return globals()[name + str(id(name))]

define("PI",3.142)

print(constant("PI"))

Wygląda na to, że stworzy styl PHP stała.

W rzeczywistości wystarczy, aby ktoś zmienił wartość jest to:

globals()["PI"+str(id("PI"))] = 3.1415

To samo dotyczy wszystkich innych rozwiązań, które tutaj znajdziesz - nawet tych sprytnych, które tworzą klasę i redefiniują metodę atrybutów set-zawsze będzie można je obejść. Taki właśnie jest Python.

Zalecam unikanie kłopotów i pisanie identyfikatorów wielkimi literami. To nie byłaby prawdziwa stała, ale potem znowu nic.

 0
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-23 14:02:11

(ten akapit miał być komentarzem do tych odpowiedzi TUTAJ i tam , które wspominały namedtuple, ale robi się zbyt długo, aby pasować do komentarza, więc zaczyna się.)

Wymienione powyżej podejście jest zdecydowanie innowacyjne. Ze względu na kompletność, na końcu nazwanej sekcji jej oficjalnej dokumentacji , czytamy:

Wyliczone stałe mogą być zaimplementowane z nazwanymi krotkami, ale jest to prostsze i bardziej efektywne użycie prostej deklaracji klasy:

class Status:
    open, pending, closed = range(3)

Innymi słowy, oficjalna dokumentacja woli używać praktycznego sposobu, a nie faktycznie implementować zachowanie tylko do odczytu. Wydaje mi się, że to kolejny przykład Zen Pythona :

Proste jest lepsze niż złożone. Praktyczność bije czystość.
 0
Author: RayLuo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-06 00:05:43

Jest czystszy sposób, aby to zrobić z namedtuple:

from collections import namedtuple


def make_consts(name, **kwargs):
    return namedtuple(name, kwargs.keys())(**kwargs)

Przykład Użycia

CONSTS = make_consts("baz1",
                     foo=1,
                     bar=2)

Z tym dokładnie podejściem można nazwać swoje stałe.

 0
Author: Juan Ignacio Sánchez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-13 05:01:01