na verdade, a maneira de criar variáveis somente leitura é possível através da função de propriedade / decorador do python . a resposta de inv é um exemplo de uso personalizado disso. A propriedade é de uso mais geral do que isso, porém, uma boa análise de como funciona está nos atributos e métodos do Python de Shalabh Chaturvedi .
N611x007
20
IMHO, forçar a constância "não é pitônico". No Python 2.7, você pode até escrever True=Falsee depois (2+2==4)==Trueretornar False.
osa
8
Como outras respostas sugerem, não há como ou não é necessário declarar constantes. Mas você pode ler este PEP sobre convenções. por exemplo THIS_IS_A_CONSTANT
Rasika Perera
34
@osa: Você não pode fazer isso em python 3 - SyntaxError: can't assign to keyword. Isso parece uma coisa boa.
precisa saber é o seguinte
3
Surpreendido, isso não foi mencionado até agora, mas Enums parece uma boa maneira de definir constantes enumeradas.
cs95 9/06/19
Respostas:
973
Não, não há. Você não pode declarar uma variável ou valor como constante no Python. Só não mude.
Se você estiver em uma classe, o equivalente seria:
classFoo(object):
CONST_NAME ="Name"
se não, é apenas
CONST_NAME ="Name"
Mas você pode dar uma olhada no snippet de código Constants in Python de Alex Martelli.
No Python 3.8, há uma typing.Finalanotação de variável que informa aos verificadores de tipo estático (como mypy) que sua variável não deve ser reatribuída. Este é o equivalente mais próximo do Java final. No entanto, na verdade, não impede a reatribuição :
from typing importFinal
a:Final=1# Executes fine, but mypy will report an error if you run mypy on this:
a =2
Em vez disso, faça o que está em "Constantes no Python", você deve usar a função ou o decorador "property".
Seth Johnson
26
As pessoas perguntam sobre o mesmo recurso no Perl. Existe um módulo de importação chamado "use constant", mas (AFAIK) é apenas um invólucro para criar uma função minúscula que retorna o valor. Eu faço o mesmo em Python. Exemplo:def MY_CONST_VALUE(): return 123
kevinarpe 17/12/12
8
"Não, não há." É verdade, mas com base no trabalho de outras pessoas, eu adicionei uma resposta, bem abaixo, com uma implementação curta e simples de "Constantes" para python 2.7 (que carece de "enum"). Eles são apenas para leitura do tipo enum name.attributee podem conter qualquer valor. A declaração é fácil Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0), o uso é direto print 10 + Nums.PI, tente alterar os resultados na exceção Nums.PI = 22=> ValueError (..).
Home
110
Só não mude. você fez o meu dia
Hi-Angel
89
"Apenas não mude" não ajuda em nada. Ele não responde à pergunta e eu sugiro que ela seja removida.
Bartek Banachewicz
354
Não há constpalavras-chave como em outros idiomas, no entanto, é possível criar uma Propriedade que tenha uma "função getter" para ler os dados, mas nenhuma "função setter" para reescrever os dados. Isso essencialmente protege o identificador de ser alterado.
Aqui está uma implementação alternativa usando a propriedade de classe:
Observe que o código está longe de ser fácil para um leitor se perguntando sobre constantes. Veja a explicação abaixo
Observe que o decorador @apply parece estar obsoleto.
Para definir o identificador FOO, os primeiros definem duas funções (fset, fget - os nomes estão à minha escolha).
Em seguida, use a propertyfunção interna para construir um objeto que possa ser "definido" ou "obter".
Observe que os propertydois primeiros parâmetros da função são nomeados fsete fget.
Use o fato de escolhermos esses nomes para nosso próprio getter & setter e crie um dicionário de palavras-chave usando o ** (asterisco duplo) aplicado a todas as definições locais desse escopo para passar parâmetros para a propertyfunção
Com base na documentação AttributeErrore TypeError, acho que a exceção levantada deve ser um novo erro, que proponho nomeação ConstantErrorou algo parecido, que é uma subclasse de TypeError. A seção na documentação que me faz pensar que: docs.python.org/2/library/exceptions.html
ArtOfWarfare
3
Estou surpreso com este código. Por que a fonte dos métodos FOO () e BAR () tem auto como argumento? Meu IDE sublinha os colchetes no vermelho (erro de "compilação"). Eu cansei de me colocar nele, mas então eu recebo um erro.
precisa saber é o seguinte
10
Indo para esses comprimentos delineia uma clara deficiência na linguagem python. Por que eles não sentiram a necessidade de adicionar isso ao Python 3. Não acredito que ninguém o sugeriu e simplesmente não consigo ver a lógica por trás de algum comitê que fica nah, constantes? não.
Andrew S
8
E sua solução ainda pode ser modificado por um programador python determinado usandoCONST.__dict__['FOO'] = 7
pppery
11
@OscarSmith, acho que melhoraria o design do 'código auto-documentado'. Quando explico no código que algum valor não pode mudar, é mais fácil entender do que ler todo o código-fonte e perceber que algum valor nunca muda. Além disso, bloqueia a possibilidade de alguém alterar um valor que deve ser, bem, constante. Lembre-se: explícito é melhor que implícito.
Gabriel
112
No Python, em vez de a linguagem impor algo, as pessoas usam convenções de nomenclatura, por exemplo, __methodpara métodos privados e _methodmétodos protegidos.
Portanto, da mesma maneira, você pode simplesmente declarar a constante como todos os limites, por exemplo
MY_CONSTANT ="one"
Se você quiser que essa constante nunca mude, poderá conectar-se ao acesso a atributos e fazer truques, mas uma abordagem mais simples é declarar uma função
def MY_CONSTANT():return"one"
O único problema está em todo lugar que você terá que fazer MY_CONSTANT (), mas novamente MY_CONSTANT = "one"é a maneira correta em python (geralmente).
Você também pode usar o namedtuple para criar constantes:
>>>from collections import namedtuple
>>>Constants= namedtuple('Constants',['pi','e'])>>> constants =Constants(3.14,2.718)>>> constants.pi
3.14>>> constants.pi =3Traceback(most recent call last):File"<stdin>", line 1,in<module>AttributeError: can't set attribute
Fazer def MY_CONSTANT(): return "one"não impedirá alguém, posteriormente no código, de fazer MY_CONSTANT = "two"(ou redeclarar a função).
Matthew Schinckel
6
@MatthewSchinckel, trata-se de convenção, mudar também MY_CONSTANT não mudará o uso MY_CONSTANT (), mas gerará erro e, em python, se você quiser, pode mudar qualquer coisa, nenhum truque inteligente pode protegê-lo.
Anurag Uniyal
3
Agradecemos por apresentar a abordagem de nome duplo. Definitivamente inovador. Você também pode encontrar meu "comentário" aqui relevante.
RayLuo 6/09/19
@ MatthewSchinckel, você pode redefinir QUALQUER COISA em python, então isso não é realmente um bom argumento.
cslotty 2/03
@MatthewSchinckel A idéia não é escrever MY_CONSTANT = MY_CONSTANT(), mas usar MY_CONSTANT()como constante. Claro que sim. Mas isso é bom e está muito alinhado com o princípio do python "Somos todos adultos aqui" - ou seja, o desenvolvedor raramente será proibido de decidir substituir uma regra quando tiver boas razões e saber o que está fazendo.
jonathan.scholbach
69
Recentemente, eu encontrei uma atualização muito sucinta disso, que gera automaticamente mensagens de erro significativas e impede o acesso via __dict__:
class CONST(object):
__slots__ =()
FOO =1234
CONST = CONST()# ----------print(CONST.FOO)# 1234
CONST.FOO =4321# AttributeError: 'CONST' object attribute 'FOO' is read-only
CONST.__dict__['FOO']=4321# AttributeError: 'CONST' object has no attribute '__dict__'
CONST.BAR =5678# AttributeError: 'CONST' object has no attribute 'BAR'
Definimos sobre nós mesmos como nos tornar uma instância e, em seguida, usamos slots para garantir que nenhum atributo adicional possa ser adicionado. Isso também remove a __dict__rota de acesso. Obviamente, todo o objeto ainda pode ser redefinido.
Editar - Solução original
Provavelmente estou perdendo um truque aqui, mas isso parece funcionar para mim:
Criar a instância permite que o __setattr__método mágico entre e intercepte as tentativas de definir a FOOvariável. Você poderia lançar uma exceção aqui, se quisesse. A instanciação da instância sobre o nome da classe impede o acesso diretamente através da classe.
É uma dor total para um valor, mas você pode anexar muito ao seu CONSTobjeto. Tendo uma classe alta, o nome da classe também parece um pouco grotty, mas acho que é bastante sucinto no geral.
Essa é a melhor e mais clara resposta, pois possui o menor "mecanismo", mas a maior funcionalidade. Gerar uma exceção é importante ... não é uma opção.
Erik Aronesty
Eu elaborei uma rota mais curta que produz automaticamente erros significativos, mas é muito parecida com o mesmo. Deixei a ideia original aqui para comparação.
Jon Betts
Que pena que você ainda precise desse CONST.prefixo. Também em situações com vários módulos, isso será complicado.
Alfe
1
Eu acho que normalmente você gostaria de agrupar constantes em alguns pacotes relacionados de qualquer maneira nessa situação (em vez de ter um objeto CONST gigante), então provavelmente não é uma coisa tão ruim.
Jon Betts
Por que essa resposta ainda está tão longe ?! A __slots__solução é tão elegante e eficaz. De tudo o que li, isso é o mais próximo possível da criação de constantes no Python. Muito obrigado. E para todos os interessados, aqui está uma explicação brilhante e profunda da __slots__mágica.
JohnGalt
34
Python não tem constantes.
Talvez a alternativa mais fácil seja definir uma função para ela:
def MY_CONSTANT():return42
MY_CONSTANT() agora tem toda a funcionalidade de uma constante (mais algumas chaves irritantes).
Eu só queria adicionar essa sugestão, mas felizmente rolei para as respostas de baixa classificação. Espero que seja mais votado e concordo plenamente que ele tem toda a funcionalidade de uma constante e é muito simples e direto. Olhando para a quantidade de código padrão em todas as soluções sofisticadas, acho as chaves relativamente desagradáveis.
yaccob
1
esta é a resposta mais simples, embora deva-se notar que ela possui alguma sobrecarga e não interromperá os idiotas que modificam o valor de retorno. Ela só vai impedir que o código mais abaixo da linha como alterar a origem
MrMesees
@MrMesees modificando o valor de retorno? Você quer dizer editar a fonte? Mas a partir disso, você não está protegido nem mesmo em C ++, onde constantes (como constexpr) são constantes reais.
Ruslan
@Ruslan, o que eu quis dizer foi que, como o python não tem constexpr, ele não interrompe a edição do valor depois que ele é retornado para um contexto externo. Nada foi feito para 42 para impor o estado congelado neste exemplo.
MrMesees
20
Além das duas respostas principais (basta usar variáveis com nomes UPPERCASE ou usar propriedades para tornar os valores somente leitura), quero mencionar que é possível usar metaclasses para implementar constantes nomeadas . Eu forneço uma solução muito simples usando metaclasses no GitHub, que pode ser útil se você quiser que os valores sejam mais informativos sobre seu tipo / nome:
>>>from named_constants importConstants>>>classColors(Constants):... black =0... red =1... white =15...>>> c =Colors.black
>>> c ==0True>>> c
Colors.black
>>> c.name()'black'>>>Colors(0)is c
True
Este é um pouco mais avançado do Python, mas ainda é muito fácil de usar e prático. (O módulo possui mais alguns recursos, incluindo constantes sendo somente leitura, consulte o arquivo LEIA-ME.)
Existem soluções semelhantes flutuando em vários repositórios, mas, pelo que sei, elas não possuem um dos recursos fundamentais que eu esperaria das constantes (como sendo constante ou de tipo arbitrário) ou possuem recursos esotéricos que torná-los menos aplicáveis em geral. Mas YMMV, eu ficaria grato pelo feedback. :-)
Gosto da sua implementação no GitHub. Eu estava quase pronto para escrever uma classe básica que implementou a funcionalidade de pesquisa inversa, mas vejo que você fez isso e muito mais!
Kerr
Obrigado, @Kerr, é o primeiro feedback que recebi e me fez feliz. :-)
hans_meine 14/11
Impressionante. Eu apenas tentei isso. É bom ter isso como opção. Embora ainda não tenha decidido se me importo o suficiente com o aspecto somente leitura, use isso em vez de simplesmente fazer def enum(**enums): return type('Enum', (), enums). Numbers = enum(ONE=1, TWO=2, THREE='three'), conforme stackoverflow.com/a/1695250/199364 , seção "Nas versões anteriores ..."
ToolmakerSteve
19
As propriedades são uma maneira de criar constantes. Você pode fazer isso declarando uma propriedade getter, mas ignorando o setter. Por exemplo:
Sob solução valiosa. Acabei de implementar isso depois de encontrar esta página (e não esta resposta) e voltei para adicioná-la, se ainda não estiver. Eu queria enfatizar a utilidade desta resposta.
Marc
18
Edit: Adicionado código de exemplo para Python 3
Nota: esta outra resposta parece oferecer uma implementação muito mais completa semelhante à seguinte (com mais recursos).
Você pode usar um nomeado duplo como solução alternativa para criar efetivamente uma constante que funciona da mesma maneira que uma variável final estática em Java (uma "constante" Java). Como soluções alternativas, é meio elegante. (Uma abordagem mais elegante seria simplesmente melhorar a linguagem Python - que tipo de linguagem permite redefinir math.pi? -, mas discordo.)
(Enquanto escrevo isso, percebo outra resposta para essa pergunta mencionada nomeadaple, mas continuarei aqui porque mostrarei uma sintaxe que se aproxima mais do que você esperaria em Java, pois não há necessidade de criar uma nomeada digite como nome nomeado força você a fazer.)
Seguindo o seu exemplo, você se lembrará de que em Java devemos definir a constante dentro de alguma classe ; porque você não mencionou o nome de uma classe, vamos chamá-lo Foo. Aqui está a classe Java:
public classFoo{
public static final String CONST_NAME ="Name";}
Aqui está o Python equivalente.
from collections import namedtuple
Foo= namedtuple('_Foo','CONST_NAME')('Name')
O ponto principal que quero acrescentar aqui é que você não precisa de um Footipo separado (uma "tupla nomeada anônima" seria legal, mesmo que pareça um oxímoro), por isso nomeamos nosso nome nomeado _Foopara que, esperemos, não escape para a importação de módulos.
O segundo ponto aqui é que criamos imediatamente uma instância do nametuple, chamando-o Foo; não é necessário fazer isso em uma etapa separada (a menos que você queira). Agora você pode fazer o que pode fazer em Java:
>>>Foo.CONST_NAME
'Name'
Mas você não pode atribuir a ele:
>>>Foo.CONST_NAME ='bar'…AttributeError: can't set attribute
Agradecimento: Pensei ter inventado a abordagem do duplo nome, mas depois vejo que alguém deu uma resposta semelhante (embora menos compacta). Também notei o que são "tuplas nomeadas" no Python? , que salienta que sys.version_infoagora é um nome múltiplo, talvez a biblioteca padrão do Python já tenha tido essa ideia muito antes.
Observe que, infelizmente (ainda sendo Python), você pode apagar toda a Fooatribuição:
>>>Foo='bar'
(facepalm)
Mas pelo menos estamos impedindo que o Foo.CONST_NAMEvalor seja alterado, e isso é melhor que nada. Boa sorte.
Aqui está uma implementação de uma classe "Constants", que cria instâncias com atributos somente leitura (constantes). Por exemplo, pode usar Nums.PIpara obter um valor que foi inicializado como 3.14159e Nums.PI = 22gera uma exceção.
# ---------- Constants.py ----------classConstants(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:raiseValueError("setattr while locked", self)if(__name__ =="__main__"):# Usage example.Nums=Constants(ONE=1, PI=3.14159,DefaultWidth=100.0)print10+Nums.PI
print'----- Following line is deliberate ValueError -----'Nums.PI =22
Graças ao FrozenDict de @MikeGraham , que usei como ponto de partida. Alterado, portanto, em vez da Nums['ONE']sintaxe de uso Nums.ONE.
E, graças à resposta de @ Raufio, pela ideia de substituir __ setattr __.
Ou para uma implementação com mais funcionalidade, consulte named_constants do
@Hans_meine no GitHub
Python é uma linguagem de adultos que consentem. Não há proteção contra algo assim. Nums._d['PI'] = 22 A linguagem em si não fornece nenhuma maneira de marcar as coisas como não mutáveis, acredito.
precisa
8
Uma tupla tecnicamente é qualificada como uma constante, pois ela gera um erro se você tentar alterar um de seus valores. Se você deseja declarar uma tupla com um valor, coloque uma vírgula após seu único valor, desta forma:
my_tuple =(0"""Or any other value""",)
Para verificar o valor dessa variável, use algo semelhante a este:
if my_tuple[0]==0:#Code goes here
Se você tentar alterar esse valor, um erro será gerado.
Eu faria uma classe que substituísse o __setattr__método da classe de objeto base e envolvesse minhas constantes com isso, observe que estou usando o python 2.7:
class const(object):def __init__(self, val):
super(const, self).__setattr__("value", val)def __setattr__(self, name, val):raiseValueError("Trying to change a constant value", self)
Para quebrar uma sequência:
>>> 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'
É bem simples, mas se você quiser usar suas constantes da mesma forma que faria com um objeto não constante (sem usar constObj.value), será um pouco mais intenso. É possível que isso possa causar problemas; portanto, é melhor manter o .valueprograma para mostrar e saber que você está fazendo operações com constantes (embora talvez não seja o modo mais 'pitônico').
+1 para uma abordagem interessante. Embora não seja tão limpo quanto as respostas que já foram fornecidas. E mesmo a solução def ONE(): return 1mais simples sugerida anteriormente é mais fácil de usar do ONE()que esta resposta ONE.value.
Home
7
Infelizmente, o Python ainda não tem constantes e é uma pena. O ES6 já adicionou constantes de suporte ao JavaScript ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ), pois é algo muito útil em qualquer linguagem de programação. Conforme respondido em outras respostas na comunidade Python, use a variável convention - user uppercase como constantes, mas ela não protege contra erros arbitrários no código. Se desejar, pode ser considerada uma solução de arquivo único útil a seguir (consulte as instruções de como usá-la).
arquivo constants.py
import collections
__all__ =('const',)classConstant(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__:raiseTypeError('Constanst can not be changed')ifnot isinstance(value, collections.Hashable):if isinstance(value, list):
value = tuple(value)elif isinstance(value, set):
value = frozenset(value)elif isinstance(value, dict):raiseTypeError('dict can not be used as constant')else:raiseValueError('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__:raiseTypeError('Constanst can not be deleted')raiseNameError("name '%s' is not defined"% name)def __call__(self):"""Return all constans."""return self.__dict__
const =Constant()if __name__ =='__main__':import doctest
doctest.testmod()
Se isso não for suficiente, consulte o caso de teste completo.
import decimal
import uuid
import datetime
import unittest
from..constants importConstantclassTestConstant(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 =.211def 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 =.211def 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 =.211def 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 =.211def 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 =Falsedef 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 =3212def 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 =Truedef 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 =Truedef 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 =Nonedef 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 =Nonedef 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 =1def 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"})
Vantagens: 1. Acesso a todas as constantes para todo o projeto 2. Controle rigoroso dos valores das constantes
Falta: 1. Não suporta tipos personalizados e o tipo 'dict'
Notas:
Testado com Python3.4 e Python3.5 (eu uso o 'tox' para isso)
Ambiente de teste:
.
$ uname -a
Linux wlysenko-Aspire3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
Você pode melhorar isso ligeiramente convertendo dicionários automaticamente para tuplas nomeadas
Peter Schorn
6
A maneira Pythonic de declarar "constantes" é basicamente uma variável no nível do módulo:
RED =1
GREEN =2
BLUE =3
E então escreva suas classes ou funções. Como as constantes são quase sempre inteiras e também são imutáveis no Python, você tem muito pouca chance de alterá-la.
A menos, é claro, se você definir explicitamente RED = 2.
Sim, mas bloquear a capacidade de "definir explicitamente RED = 2" é o benefício inteiro (em outros idiomas) de poder declarar um nome de variável como "constante"!
Página
6
Você se beneficiaria com isso? A coisa mais útil sobre const é geralmente otimizações de compilador que não são realmente uma coisa no Python. Quer que algo seja constante? Só não mude. Se você está preocupado com alguém que está mudando, você pode simplesmente colocá-lo fora do escopo deles ou apenas perceber que, se alguém está mudando, isso é problema deles e eles precisam lidar com isso, não você.
Kevin
@ Kevin: " Você se beneficiaria com ... ", o benefício de staticter um único armazenamento para o valor de todas as instâncias de uma classe? A menos que haja a possibilidade de declarar uma variável estática / classe de fato.
mins
8
O problema principal é que alguns podem vê-lo como um valor que é uma fonte de verdade, incapaz de ser alterado, e usá-lo como fonte de verdade em todo o código, em vez de introduzir valores mágicos (que eu vejo muito em Python) - e outros podem vê-lo como algo que eles podem mudar à vontade. Quando alguém altera uma variável global e você não pode dizer onde ela foi alterada, e o aplicativo trava porque RED = "azul" em vez de "vermelho", você está apresentando um problema totalmente desnecessário que já foi resolvido de maneira simples e simples. é universalmente entendido.
Dagrooms
5
Podemos criar um objeto descritor.
classConstant:def __init__(self,value=None):
self.value = value
def __get__(self,instance,owner):return self.value
def __set__(self,instance,value):raiseValueError("You can't change a constant")
1) Se quisermos trabalhar com constantes no nível da instância, então:
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 =100Traceback(most recent call last):File"<stdin>", line 1,in<module>ValueError:You can't change a constant
2) se desejássemos criar constantes apenas no nível de classe, poderíamos usar uma metaclasse que serve como um contêiner para nossas constantes (nossos objetos descritores); todas as classes descendentes herdarão nossas constantes (nossos objetos descritores) sem nenhum risco que possa ser modificado.
# metaclass of my class FooclassFooMeta(type):pass# class FooclassFoo(metaclass=FooMeta):pass# I create constants in my metaclassFooMeta.NUM =Constant(0xff)FooMeta.NAME =Constant('FOO')>>>Foo.NUM #=> 255>>>Foo.NAME #=> 'FOO'>>>Foo.NUM =0#=> ValueError: You can't change a constant
Se eu criar uma subclasse de Foo, essa classe herdará a constante sem a possibilidade de modificá-la
classBar(Foo):pass>>>Bar.NUM #=> 255>>>Bar.NUM =0#=> ValueError: You can't change a constant
Em python, uma constante é simplesmente uma variável com um nome em todas as maiúsculas, com palavras separadas pelo caractere sublinhado,
por exemplo
DAYS_IN_WEEK = 7
O valor é mutável, pois você pode alterá-lo. Mas, dadas as regras do nome, é uma constante, por que você o faria? Quero dizer, é o seu programa, afinal!
Essa é a abordagem adotada no python. Não há privatepalavra-chave pelo mesmo motivo. Prefixe o nome com um sublinhado e você sabe que ele deve ser privado. O código pode violar a regra .... assim como um programador pode remover a palavra-chave privada de qualquer maneira.
O Python poderia ter adicionado uma constpalavra - chave ... mas um programador pode remover a palavra-chave e alterar a constante, se quiser, mas por que fazer isso? Se você quiser violar a regra, poderá alterá-la de qualquer maneira. Mas por que se preocupar em quebrar a regra se o nome deixa clara a intenção?
Talvez haja algum teste de unidade em que faça sentido aplicar uma alteração no valor? Para ver o que acontece durante uma semana de 8 dias, embora no mundo real o número de dias da semana não possa ser alterado. Se o idioma o impedisse de fazer uma exceção, se houver apenas um caso, você precisará violar a regra ... você teria que parar de declará-lo como uma constante, mesmo que ainda seja uma constante no aplicativo, e exista apenas este caso de teste que vê o que acontece se for alterado.
O nome todo em maiúsculas informa que ele pretende ser uma constante. Isso é o que é importante. Não é uma linguagem que força restrições no código que você pode alterar de qualquer maneira.
Não existe uma maneira perfeita de fazer isso. Pelo que entendi, a maioria dos programadores apenas coloca o identificador em maiúscula, portanto PI = 3.142 pode ser facilmente entendido como uma constante.
Por outro lado, se você quer algo que realmente age como uma constante, não tenho certeza de que o encontrará. Com qualquer coisa que você faça, sempre haverá uma maneira de editar a "constante", para que não seja realmente uma constante. Aqui está um exemplo muito simples e sujo:
É o mesmo para todas as outras soluções que você encontrará aqui - mesmo as mais inteligentes que formam uma classe e redefinem o método set attribute - sempre haverá uma maneira de contorná-las. É assim que o Python é.
Minha recomendação é evitar todo o aborrecimento e apenas colocar seus identificadores em maiúscula. Não seria realmente uma constante adequada, mas, novamente, nada seria.
Para quem está lendo isso, lembre-se de que, se você definir um objeto mutável como uma dessas constantes, qualquer um poderá alterar seu valor interno. por exemplo, vamos bar = [1, 2, 3], então você pode fazer o seguinte: CONSTS.bar [1] = 'a' e não será rejeitado. Portanto, tenha cuidado com isso.
Juan Ignacio Sánchez
Em vez desse método hacky, que eu criei apenas por diversão, recomendo usar o decorador de propriedades do Python.
(Este parágrafo foi feito para ser um comentário sobre as respostas aqui e ali , que mencionamos namedtuple, mas está demorando muito para caber em um comentário, então, aqui vai.)
A abordagem de nomeação dupla mencionada acima é definitivamente inovadora. Para fins de completude, porém, no final da seção NamedTuple de sua documentação oficial , ele lê:
constantes enumeradas podem ser implementadas com tuplas nomeadas, mas é mais simples e mais eficiente usar uma declaração de classe simples:
classStatus:
open, pending, closed = range(3)
Em outras palavras, a documentação oficial prefere usar uma maneira prática, em vez de realmente implementar o comportamento somente leitura. Eu acho que se torna mais um exemplo do Zen of Python :
Aqui está uma coleção de idiomas que criei como uma tentativa de melhorar algumas das respostas já disponíveis.
Eu sei que o uso de constante não é pitônico, e você não deve fazer isso em casa!
No entanto, Python é uma linguagem tão dinâmica! Este fórum mostra como é possível a criação de construções que pareçam constantes. Esta resposta tem como objetivo principal explorar o que pode ser expresso pelo idioma.
Neste post, chamarei uma variável constante para uma referência constante a valores (imutáveis ou não). Além disso, digo que uma variável tem um valor congelado quando faz referência a um objeto mutável que um código de cliente não pode atualizar seu (s) valor (es).
Um espaço de constantes (SpaceConstants)
Esse idioma cria o que parece ser um espaço para nome de variáveis constantes (também conhecido como SpaceConstants). É uma modificação de um trecho de código por Alex Martelli para evitar o uso de objetos de módulo. Em particular, essa modificação usa o que eu chamo de fábrica de classes porque, dentro da função SpaceConstants , uma classe chamada SpaceConstants é definida e uma instância dela é retornada.
Explorei o uso do class factory para implementar um design baseado em políticas em Python no stackoverflow e também em um blog .
Um espaço de valores congelados (SpaceFrozenValues)
Este próximo idioma é uma modificação dos SpaceConstants em que objetos mutáveis referenciados são congelados. Esta implementação explora o que eu chamo de fecho partilhado entre SetAttr e GetAttr funções. O valor do objeto mutável é copiado e referenciado pelo cache variável definido dentro do fechamento compartilhado da função. Ele forma o que eu chamo de cópia protegida de fechamento de um objeto mutável .
Você deve ter cuidado ao usar esse idioma, porque o getattr retorna o valor do cache fazendo uma cópia detalhada . Esta operação pode ter um impacto significativo no desempenho de objetos grandes!
from copy import deepcopy
defSpaceFrozenValues():
cache ={}def setattr(self, name, value):nonlocal cache
if name in cache:raiseAttributeError("Cannot reassign members")
cache[name]= deepcopy(value)def getattr(self, name):nonlocal cache
if name notin cache:raiseAttributeError("Object has no attribute '{}'".format(name))return deepcopy(cache[name])
cls = type('SpaceFrozenValues',(),{'__getattr__': getattr,'__setattr__': setattr
})return cls()
fv =SpaceFrozenValues()print(fv.x)# AttributeError: Object has no attribute 'x'
fv.x =2# bind attribute xprint(fv.x)# print "2"
fv.x =3# raise "AttributeError: Cannot reassign members"
fv.y ={'name':'y','value':2}# bind attribute yprint(fv.y)# print "{'name': 'y', 'value': 2}"
fv.y['name']='yprime'# you can try to change mutable objectsprint(fv.y)# print "{'name': 'y', 'value': 2}"
fv.y ={}# raise "AttributeError: Cannot reassign members"
Um espaço constante (ConstantSpace)
Esse idioma é um espaço para nome imutável de variáveis constantes ou ConstantSpace . É uma combinação da resposta incrivelmente simples de Jon Betts no stackoverflow com uma fábrica de classes .
defConstantSpace(**args):
args['__slots__']=()
cls = type('ConstantSpace',(), args)return cls()
cs =ConstantSpace(
x =2,
y ={'name':'y','value':2})print(cs.x)# print "2"
cs.x =3# raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"print(cs.y)# print "{'name': 'y', 'value': 2}"
cs.y['name']='yprime'# mutable object can be changedprint(cs.y)# print "{'name': 'yprime', 'value': 2}"
cs.y ={}# raise "AttributeError: 'ConstantSpace' object attribute 'x' is read-only"
cs.z =3# raise "AttributeError: 'ConstantSpace' object has no attribute 'z'"
Um espaço congelado (FrozenSpace)
Esse idioma é um espaço para nome imutável de variáveis congeladas ou FrozenSpace . É derivado do padrão anterior, tornando cada variável uma propriedade protegida pelo fechamento da classe FrozenSpace gerada .
from copy import deepcopy
defFreezeProperty(value):
cache = deepcopy(value)return property(lambda self: deepcopy(cache))defFrozenSpace(**args):
args ={k:FreezeProperty(v)for k, v in args.items()}
args['__slots__']=()
cls = type('FrozenSpace',(), args)return cls()
fs =FrozenSpace(
x =2,
y ={'name':'y','value':2})print(fs.x)# print "2"
fs.x =3# raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"print(fs.y)# print "{'name': 'y', 'value': 2}"
fs.y['name']='yprime'# try to change mutable objectprint(fs.y)# print "{'name': 'y', 'value': 2}"
fs.y ={}# raise "AttributeError: 'FrozenSpace' object attribute 'x' is read-only"
fs.z =3# raise "AttributeError: 'FrozenSpace' object has no attribute 'z'"
No Python, as constantes não existem, mas você pode indicar que uma variável é uma constante e não deve ser alterada, adicionando CONST_ao início do nome da variável e afirmando que é uma constante em um comentário:
myVariable =0
CONST_daysInWeek =7# This is a constant - do not change its value.
CONSTANT_daysInMonth =30# This is also a constant - do not change this value.
Como alternativa, você pode criar uma função que atua como uma constante:
No meu caso, eu precisava de marcadores de distância imutáveis para a implementação de uma biblioteca de criptografia contendo muitos números literais que eu queria garantir que fossem constantes.
Esta resposta funciona, mas a tentativa de reatribuição de elementos de bytearray não gera um erro.
def const(func):'''implement const decorator'''def fset(self, val):'''attempting to set a const raises `ConstError`'''classConstError(TypeError):'''special exception for const reassignment'''passraiseConstErrordef fget(self):'''get a const'''return func()return property(fget, fset)classConsts(object):'''contain all constants'''@constdef C1():'''reassignment to C1 fails silently'''return bytearray.fromhex('deadbeef')@constdef pi():'''is immutable'''return3.141592653589793
As constantes são imutáveis, mas a atribuição constante de um bytearray falha silenciosamente:
>>> 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
raiseConstError
__main__.ConstError>>> c.C1[0]=0>>> c.C1[0]222>>> c.C1
bytearray(b'\xde\xad\xbe\xef')
Uma abordagem mais poderosa, simples e talvez até mais 'pitônica' envolve o uso de objetos memoryview (objetos de buffer em <= python-2.6).
import sys
PY_VER = sys.version.split()[0].split('.')if int(PY_VER[0])==2:if int(PY_VER[1])<6:raiseNotImplementedErrorelif int(PY_VER[1])==6:
memoryview = buffer
classConstArray(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)
A atribuição de itens do ConstArray é TypeError:
>>> C1 =ConstArray('deadbeef')>>> C1[0]=0Traceback(most recent call last):File"<stdin>", line 1,in<module>TypeError:'ConstArray' object does not support item assignment
>>> C1[0]222
Eu escrevo uma lib util para python const:
kkconst - pypi
support str, int, float, datetime
a instância do campo const manterá seu comportamento do tipo base.
Por exemplo:
from __future__ import print_function
from kkconst import(BaseConst,ConstFloatField,)classMathConst(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.6180339887print(magic_num.verbose_name)# Golden Ratio
mais detalhes sobre o uso, você pode ler o pypi url:
pypi ou github
Você pode agrupar uma constante em uma matriz numpy, sinalizá-la apenas para gravação e sempre chamá-la pelo índice 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
é claro que isso apenas protege o conteúdo do numpy, não a variável "CONSTANT"; você ainda pode fazer:
CONSTANT ='foo'
e CONSTANTmudaria, no entanto, isso lançaria rapidamente um TypeError na primeira vez em que CONSTANT[0]for chamado posteriormente no script.
embora ... suponho que, em algum momento, você tenha alterado para
CONSTANT =[1,2,3]
agora você não receberá mais o TypeError. hmmmm ....
True=False
e depois(2+2==4)==True
retornarFalse
.SyntaxError: can't assign to keyword
. Isso parece uma coisa boa.Respostas:
Não, não há. Você não pode declarar uma variável ou valor como constante no Python. Só não mude.
Se você estiver em uma classe, o equivalente seria:
se não, é apenas
Mas você pode dar uma olhada no snippet de código Constants in Python de Alex Martelli.
No Python 3.8, há uma
typing.Final
anotação de variável que informa aos verificadores de tipo estático (como mypy) que sua variável não deve ser reatribuída. Este é o equivalente mais próximo do Javafinal
. No entanto, na verdade, não impede a reatribuição :fonte
def MY_CONST_VALUE(): return 123
name.attribute
e podem conter qualquer valor. A declaração é fácilNums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0)
, o uso é diretoprint 10 + Nums.PI
, tente alterar os resultados na exceçãoNums.PI = 22
=> ValueError (..).Não há
const
palavras-chave como em outros idiomas, no entanto, é possível criar uma Propriedade que tenha uma "função getter" para ler os dados, mas nenhuma "função setter" para reescrever os dados. Isso essencialmente protege o identificador de ser alterado.Aqui está uma implementação alternativa usando a propriedade de classe:
Observe que o código está longe de ser fácil para um leitor se perguntando sobre constantes. Veja a explicação abaixo
Código Explicação:
constant
que pega uma expressão e a usa para construir um "getter" - uma função que retorna apenas o valor da expressão.constant
função que acabamos de criar como decoração para definir rapidamente propriedades somente leitura.E de alguma outra maneira mais antiquada:
(O código é bastante complicado, mais explicações abaixo)
Observe que o decorador @apply parece estar obsoleto.
property
função interna para construir um objeto que possa ser "definido" ou "obter".property
dois primeiros parâmetros da função são nomeadosfset
efget
.property
funçãofonte
AttributeError
eTypeError
, acho que a exceção levantada deve ser um novo erro, que proponho nomeaçãoConstantError
ou algo parecido, que é uma subclasse deTypeError
. A seção na documentação que me faz pensar que: docs.python.org/2/library/exceptions.htmlCONST.__dict__['FOO'] = 7
No Python, em vez de a linguagem impor algo, as pessoas usam convenções de nomenclatura, por exemplo,
__method
para métodos privados e_method
métodos protegidos.Portanto, da mesma maneira, você pode simplesmente declarar a constante como todos os limites, por exemplo
Se você quiser que essa constante nunca mude, poderá conectar-se ao acesso a atributos e fazer truques, mas uma abordagem mais simples é declarar uma função
O único problema está em todo lugar que você terá que fazer MY_CONSTANT (), mas novamente
MY_CONSTANT = "one"
é a maneira correta em python (geralmente).Você também pode usar o namedtuple para criar constantes:
fonte
def MY_CONSTANT(): return "one"
não impedirá alguém, posteriormente no código, de fazerMY_CONSTANT = "two"
(ou redeclarar a função).MY_CONSTANT = MY_CONSTANT()
, mas usarMY_CONSTANT()
como constante. Claro que sim. Mas isso é bom e está muito alinhado com o princípio do python "Somos todos adultos aqui" - ou seja, o desenvolvedor raramente será proibido de decidir substituir uma regra quando tiver boas razões e saber o que está fazendo.Recentemente, eu encontrei uma atualização muito sucinta disso, que gera automaticamente mensagens de erro significativas e impede o acesso via
__dict__
:Definimos sobre nós mesmos como nos tornar uma instância e, em seguida, usamos slots para garantir que nenhum atributo adicional possa ser adicionado. Isso também remove a
__dict__
rota de acesso. Obviamente, todo o objeto ainda pode ser redefinido.Editar - Solução original
Provavelmente estou perdendo um truque aqui, mas isso parece funcionar para mim:
Criar a instância permite que o
__setattr__
método mágico entre e intercepte as tentativas de definir aFOO
variável. Você poderia lançar uma exceção aqui, se quisesse. A instanciação da instância sobre o nome da classe impede o acesso diretamente através da classe.É uma dor total para um valor, mas você pode anexar muito ao seu
CONST
objeto. Tendo uma classe alta, o nome da classe também parece um pouco grotty, mas acho que é bastante sucinto no geral.fonte
CONST.
prefixo. Também em situações com vários módulos, isso será complicado.__slots__
solução é tão elegante e eficaz. De tudo o que li, isso é o mais próximo possível da criação de constantes no Python. Muito obrigado. E para todos os interessados, aqui está uma explicação brilhante e profunda da__slots__
mágica.Python não tem constantes.
Talvez a alternativa mais fácil seja definir uma função para ela:
MY_CONSTANT()
agora tem toda a funcionalidade de uma constante (mais algumas chaves irritantes).fonte
constexpr
) são constantes reais.Além das duas respostas principais (basta usar variáveis com nomes UPPERCASE ou usar propriedades para tornar os valores somente leitura), quero mencionar que é possível usar metaclasses para implementar constantes nomeadas . Eu forneço uma solução muito simples usando metaclasses no GitHub, que pode ser útil se você quiser que os valores sejam mais informativos sobre seu tipo / nome:
Este é um pouco mais avançado do Python, mas ainda é muito fácil de usar e prático. (O módulo possui mais alguns recursos, incluindo constantes sendo somente leitura, consulte o arquivo LEIA-ME.)
Existem soluções semelhantes flutuando em vários repositórios, mas, pelo que sei, elas não possuem um dos recursos fundamentais que eu esperaria das constantes (como sendo constante ou de tipo arbitrário) ou possuem recursos esotéricos que torná-los menos aplicáveis em geral. Mas YMMV, eu ficaria grato pelo feedback. :-)
fonte
def enum(**enums): return type('Enum', (), enums)
.Numbers = enum(ONE=1, TWO=2, THREE='three')
, conforme stackoverflow.com/a/1695250/199364 , seção "Nas versões anteriores ..."As propriedades são uma maneira de criar constantes. Você pode fazer isso declarando uma propriedade getter, mas ignorando o setter. Por exemplo:
Você pode dar uma olhada em um artigo que escrevi para encontrar mais maneiras de usar as propriedades do Python.
fonte
Edit: Adicionado código de exemplo para Python 3
Nota: esta outra resposta parece oferecer uma implementação muito mais completa semelhante à seguinte (com mais recursos).
Primeiro, faça uma metaclasse :
Isso evita que as propriedades estáticas sejam alteradas. Em seguida, faça outra classe que use essa metaclasse:
Ou, se você estiver usando Python 3:
Isso deve impedir que os objetos da instância sejam alterados. Para usá-lo, herde:
Agora, os objetos acessados diretamente ou por meio de uma instância devem ser constantes:
Aqui está um exemplo acima em ação. Aqui está outro exemplo para o Python 3.
fonte
Você pode usar um nomeado duplo como solução alternativa para criar efetivamente uma constante que funciona da mesma maneira que uma variável final estática em Java (uma "constante" Java). Como soluções alternativas, é meio elegante. (Uma abordagem mais elegante seria simplesmente melhorar a linguagem Python - que tipo de linguagem permite redefinir
math.pi
? -, mas discordo.)(Enquanto escrevo isso, percebo outra resposta para essa pergunta mencionada nomeadaple, mas continuarei aqui porque mostrarei uma sintaxe que se aproxima mais do que você esperaria em Java, pois não há necessidade de criar uma nomeada digite como nome nomeado força você a fazer.)
Seguindo o seu exemplo, você se lembrará de que em Java devemos definir a constante dentro de alguma classe ; porque você não mencionou o nome de uma classe, vamos chamá-lo
Foo
. Aqui está a classe Java:Aqui está o Python equivalente.
O ponto principal que quero acrescentar aqui é que você não precisa de um
Foo
tipo separado (uma "tupla nomeada anônima" seria legal, mesmo que pareça um oxímoro), por isso nomeamos nosso nome nomeado_Foo
para que, esperemos, não escape para a importação de módulos.O segundo ponto aqui é que criamos imediatamente uma instância do nametuple, chamando-o
Foo
; não é necessário fazer isso em uma etapa separada (a menos que você queira). Agora você pode fazer o que pode fazer em Java:Mas você não pode atribuir a ele:
Agradecimento: Pensei ter inventado a abordagem do duplo nome, mas depois vejo que alguém deu uma resposta semelhante (embora menos compacta). Também notei o que são "tuplas nomeadas" no Python? , que salienta que
sys.version_info
agora é um nome múltiplo, talvez a biblioteca padrão do Python já tenha tido essa ideia muito antes.Observe que, infelizmente (ainda sendo Python), você pode apagar toda a
Foo
atribuição:(facepalm)
Mas pelo menos estamos impedindo que o
Foo.CONST_NAME
valor seja alterado, e isso é melhor que nada. Boa sorte.fonte
O PEP 591 possui o qualificador 'final'. A aplicação é do verificador de tipos.
Então você pode fazer:
Nota: a
Final
palavra - chave é aplicável apenas à versão Python 3.8fonte
Aqui está uma implementação de uma classe "Constants", que cria instâncias com atributos somente leitura (constantes). Por exemplo, pode usar
Nums.PI
para obter um valor que foi inicializado como3.14159
eNums.PI = 22
gera uma exceção.Graças ao FrozenDict de @MikeGraham , que usei como ponto de partida. Alterado, portanto, em vez da
Nums['ONE']
sintaxe de usoNums.ONE
.E, graças à resposta de @ Raufio, pela ideia de substituir __ setattr __.
Ou para uma implementação com mais funcionalidade, consulte named_constants do @Hans_meine no GitHub
fonte
Nums._d['PI'] = 22
A linguagem em si não fornece nenhuma maneira de marcar as coisas como não mutáveis, acredito.Uma tupla tecnicamente é qualificada como uma constante, pois ela gera um erro se você tentar alterar um de seus valores. Se você deseja declarar uma tupla com um valor, coloque uma vírgula após seu único valor, desta forma:
Para verificar o valor dessa variável, use algo semelhante a este:
Se você tentar alterar esse valor, um erro será gerado.
fonte
Eu faria uma classe que substituísse o
__setattr__
método da classe de objeto base e envolvesse minhas constantes com isso, observe que estou usando o python 2.7:Para quebrar uma sequência:
É bem simples, mas se você quiser usar suas constantes da mesma forma que faria com um objeto não constante (sem usar constObj.value), será um pouco mais intenso. É possível que isso possa causar problemas; portanto, é melhor manter o
.value
programa para mostrar e saber que você está fazendo operações com constantes (embora talvez não seja o modo mais 'pitônico').fonte
def ONE(): return 1
mais simples sugerida anteriormente é mais fácil de usar doONE()
que esta respostaONE.value
.Infelizmente, o Python ainda não tem constantes e é uma pena. O ES6 já adicionou constantes de suporte ao JavaScript ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ), pois é algo muito útil em qualquer linguagem de programação. Conforme respondido em outras respostas na comunidade Python, use a variável convention - user uppercase como constantes, mas ela não protege contra erros arbitrários no código. Se desejar, pode ser considerada uma solução de arquivo único útil a seguir (consulte as instruções de como usá-la).
arquivo constants.py
Se isso não for suficiente, consulte o caso de teste completo.
Vantagens: 1. Acesso a todas as constantes para todo o projeto 2. Controle rigoroso dos valores das constantes
Falta: 1. Não suporta tipos personalizados e o tipo 'dict'
Notas:
Testado com Python3.4 e Python3.5 (eu uso o 'tox' para isso)
Ambiente de teste:
.
fonte
A maneira Pythonic de declarar "constantes" é basicamente uma variável no nível do módulo:
E então escreva suas classes ou funções. Como as constantes são quase sempre inteiras e também são imutáveis no Python, você tem muito pouca chance de alterá-la.
A menos, é claro, se você definir explicitamente
RED = 2
.fonte
RED = 2
" é o benefício inteiro (em outros idiomas) de poder declarar um nome de variável como "constante"!static
ter um único armazenamento para o valor de todas as instâncias de uma classe? A menos que haja a possibilidade de declarar uma variável estática / classe de fato.Podemos criar um objeto descritor.
1) Se quisermos trabalhar com constantes no nível da instância, então:
2) se desejássemos criar constantes apenas no nível de classe, poderíamos usar uma metaclasse que serve como um contêiner para nossas constantes (nossos objetos descritores); todas as classes descendentes herdarão nossas constantes (nossos objetos descritores) sem nenhum risco que possa ser modificado.
Se eu criar uma subclasse de Foo, essa classe herdará a constante sem a possibilidade de modificá-la
fonte
Os dicionários Python são mutáveis, portanto, não parecem uma boa maneira de declarar constantes:
fonte
Aqui está um truque se você deseja constantes e não se importa com seus valores:
Apenas defina classes vazias.
por exemplo:
fonte
Em python, uma constante é simplesmente uma variável com um nome em todas as maiúsculas, com palavras separadas pelo caractere sublinhado,
por exemplo
DAYS_IN_WEEK = 7
O valor é mutável, pois você pode alterá-lo. Mas, dadas as regras do nome, é uma constante, por que você o faria? Quero dizer, é o seu programa, afinal!
Essa é a abordagem adotada no python. Não há
private
palavra-chave pelo mesmo motivo. Prefixe o nome com um sublinhado e você sabe que ele deve ser privado. O código pode violar a regra .... assim como um programador pode remover a palavra-chave privada de qualquer maneira.O Python poderia ter adicionado uma
const
palavra - chave ... mas um programador pode remover a palavra-chave e alterar a constante, se quiser, mas por que fazer isso? Se você quiser violar a regra, poderá alterá-la de qualquer maneira. Mas por que se preocupar em quebrar a regra se o nome deixa clara a intenção?Talvez haja algum teste de unidade em que faça sentido aplicar uma alteração no valor? Para ver o que acontece durante uma semana de 8 dias, embora no mundo real o número de dias da semana não possa ser alterado. Se o idioma o impedisse de fazer uma exceção, se houver apenas um caso, você precisará violar a regra ... você teria que parar de declará-lo como uma constante, mesmo que ainda seja uma constante no aplicativo, e exista apenas este caso de teste que vê o que acontece se for alterado.
O nome todo em maiúsculas informa que ele pretende ser uma constante. Isso é o que é importante. Não é uma linguagem que força restrições no código que você pode alterar de qualquer maneira.
Essa é a filosofia do python.
fonte
Não existe uma maneira perfeita de fazer isso. Pelo que entendi, a maioria dos programadores apenas coloca o identificador em maiúscula, portanto PI = 3.142 pode ser facilmente entendido como uma constante.
Por outro lado, se você quer algo que realmente age como uma constante, não tenho certeza de que o encontrará. Com qualquer coisa que você faça, sempre haverá uma maneira de editar a "constante", para que não seja realmente uma constante. Aqui está um exemplo muito simples e sujo:
Parece que isso fará uma constante no estilo PHP.
Na realidade, basta que alguém mude o valor:
É o mesmo para todas as outras soluções que você encontrará aqui - mesmo as mais inteligentes que formam uma classe e redefinem o método set attribute - sempre haverá uma maneira de contorná-las. É assim que o Python é.
Minha recomendação é evitar todo o aborrecimento e apenas colocar seus identificadores em maiúscula. Não seria realmente uma constante adequada, mas, novamente, nada seria.
fonte
Existe uma maneira mais limpa de fazer isso com o nomeduplo:
Exemplo de uso
Com essa abordagem exata, você pode colocar no namespace suas constantes.
fonte
Talvez a biblioteca pconst o ajude ( github ).
$ pip install pconst
[Out] Constant value of "APPLE_PRICE" is not editable.
fonte
Você pode usar StringVar ou IntVar, etc, sua constante é const_val
fonte
Você pode fazer isso com
collections.namedtuple
eitertools
:fonte
(Este parágrafo foi feito para ser um comentário sobre as respostas aqui e ali , que mencionamos
namedtuple
, mas está demorando muito para caber em um comentário, então, aqui vai.)A abordagem de nomeação dupla mencionada acima é definitivamente inovadora. Para fins de completude, porém, no final da seção NamedTuple de sua documentação oficial , ele lê:
Em outras palavras, a documentação oficial prefere usar uma maneira prática, em vez de realmente implementar o comportamento somente leitura. Eu acho que se torna mais um exemplo do Zen of Python :
fonte
Aqui está uma coleção de idiomas que criei como uma tentativa de melhorar algumas das respostas já disponíveis.
Eu sei que o uso de constante não é pitônico, e você não deve fazer isso em casa!
No entanto, Python é uma linguagem tão dinâmica! Este fórum mostra como é possível a criação de construções que pareçam constantes. Esta resposta tem como objetivo principal explorar o que pode ser expresso pelo idioma.
Por favor, não seja muito duro comigo :-).
Para mais detalhes, escrevi um blog de acompanhamento sobre esses idiomas .
Neste post, chamarei uma variável constante para uma referência constante a valores (imutáveis ou não). Além disso, digo que uma variável tem um valor congelado quando faz referência a um objeto mutável que um código de cliente não pode atualizar seu (s) valor (es).
Um espaço de constantes (SpaceConstants)
Esse idioma cria o que parece ser um espaço para nome de variáveis constantes (também conhecido como SpaceConstants). É uma modificação de um trecho de código por Alex Martelli para evitar o uso de objetos de módulo. Em particular, essa modificação usa o que eu chamo de fábrica de classes porque, dentro da função SpaceConstants , uma classe chamada SpaceConstants é definida e uma instância dela é retornada.
Explorei o uso do class factory para implementar um design baseado em políticas em Python no stackoverflow e também em um blog .
Um espaço de valores congelados (SpaceFrozenValues)
Este próximo idioma é uma modificação dos SpaceConstants em que objetos mutáveis referenciados são congelados. Esta implementação explora o que eu chamo de fecho partilhado entre SetAttr e GetAttr funções. O valor do objeto mutável é copiado e referenciado pelo cache variável definido dentro do fechamento compartilhado da função. Ele forma o que eu chamo de cópia protegida de fechamento de um objeto mutável .
Você deve ter cuidado ao usar esse idioma, porque o getattr retorna o valor do cache fazendo uma cópia detalhada . Esta operação pode ter um impacto significativo no desempenho de objetos grandes!
Um espaço constante (ConstantSpace)
Esse idioma é um espaço para nome imutável de variáveis constantes ou ConstantSpace . É uma combinação da resposta incrivelmente simples de Jon Betts no stackoverflow com uma fábrica de classes .
Um espaço congelado (FrozenSpace)
Esse idioma é um espaço para nome imutável de variáveis congeladas ou FrozenSpace . É derivado do padrão anterior, tornando cada variável uma propriedade protegida pelo fechamento da classe FrozenSpace gerada .
fonte
No Python, as constantes não existem, mas você pode indicar que uma variável é uma constante e não deve ser alterada, adicionando
CONST_
ao início do nome da variável e afirmando que é uma constante em um comentário:Como alternativa, você pode criar uma função que atua como uma constante:
fonte
No meu caso, eu precisava de marcadores de distância imutáveis para a implementação de uma biblioteca de criptografia contendo muitos números literais que eu queria garantir que fossem constantes.
Esta resposta funciona, mas a tentativa de reatribuição de elementos de bytearray não gera um erro.
As constantes são imutáveis, mas a atribuição constante de um bytearray falha silenciosamente:
Uma abordagem mais poderosa, simples e talvez até mais 'pitônica' envolve o uso de objetos memoryview (objetos de buffer em <= python-2.6).
A atribuição de itens do ConstArray é
TypeError
:fonte
Eu escrevo uma lib util para python const: kkconst - pypi support str, int, float, datetime
a instância do campo const manterá seu comportamento do tipo base.
Por exemplo:
mais detalhes sobre o uso, você pode ler o pypi url: pypi ou github
fonte
Você pode agrupar uma constante em uma matriz numpy, sinalizá-la apenas para gravação e sempre chamá-la pelo índice zero.
é claro que isso apenas protege o conteúdo do numpy, não a variável "CONSTANT"; você ainda pode fazer:
e
CONSTANT
mudaria, no entanto, isso lançaria rapidamente um TypeError na primeira vez em queCONSTANT[0]
for chamado posteriormente no script.embora ... suponho que, em algum momento, você tenha alterado para
agora você não receberá mais o TypeError. hmmmm ....
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.setflags.html
fonte