Python'da nasıl sabit oluştururum?


989

Python'da sabit bildirmenin bir yolu var mı? Java'da şu şekilde sabit değerler oluşturabiliriz:

public static final String CONST_NAME = "Name";

Python'da yukarıdaki Java sabit bildiriminin eşdeğeri nedir?


6
aslında python'un özellik fonksiyonu / dekoratörü ile salt okunur değişkenler oluşturmanın yolu mümkündür . Cevap ait inv bunun özel bir kullanım örneğidir. mülkiyet bundan daha genel bir kullanım olsa da, nasıl çalıştığının iyi bir analizi Shalabh Chaturvedi'nin Python Özellikleri ve Yöntemleri üzerindedir .
n611x007

20
IMHO, sabitliği zorunlu kılmak "pitonik değil". Python 2.7'de bile yazabilir True=Falseve sonra (2+2==4)==Truegeri dönebilirsiniz False.
osa

8
Diğer cevapların da belirttiği gibi sabitleri bildirmenin bir yolu yoktur. Ancak bu PEP'i sözleşmeler hakkında okuyabilirsiniz . örneğin THIS_IS_A_CONSTANT
Rasika Perera

34
@osa: Bunu python 3'te yapamazsın SyntaxError: can't assign to keyword. Bu iyi bir şey gibi görünüyor.
naught101

3
Şimdiye kadar bu konuya değinilmedi, ancak Numaralandırmalar numaralandırılmış sabitleri tanımlamak için iyi bir yol gibi görünüyordu.
cs95

Yanıtlar:


973

Hayır yok. Python'da bir değişkeni veya değeri sabit olarak bildiremezsiniz. Sadece değiştirmeyin.

Bir sınıftaysanız, eşdeğer:

class Foo(object):
    CONST_NAME = "Name"

değilse, sadece

CONST_NAME = "Name"

Ancak Alex Martelli'nin Python'daki kod pasajına bakabilirsiniz .


Python typing.Final3.8'den itibaren, statik tip denetleyicilere (mypy gibi) değişkeninizin yeniden atanmaması gerektiğini söyleyen bir değişken ek açıklaması vardır. Bu Java'nın en yakın eşdeğeridir final. Ancak, yeniden atanmayı gerçekten engellemez :

from typing import Final

a: Final = 1

# Executes fine, but mypy will report an error if you run mypy on this:
a = 2

27
Daha sonra "Python'daki Sabitler" bölümünde ne yapmalısınız, "özellik" işlevini veya dekoratörü kullanmalısınız.
Seth Johnson

26
İnsanlar Perl'de aynı özelliği soruyorlar. "Use sabit" adlı bir alma modülü var, ancak (AFAIK), değeri döndüren küçük bir işlev oluşturmak için sadece bir sarıcıdır. Aynı şeyi Python'da da yapıyorum. Örnek:def MY_CONST_VALUE(): return 123
kevinarpe

8
"Hayır yok." Doğru, ama diğer insanların çalışmalarına dayanarak, aşağıda, python 2.7 ("enum" eksik) için "Sabitler" kısa ve basit bir uygulama ile bir cevap ekledim. Bunlar enum benzeri salt okunurdur name.attributeve herhangi bir değer içerebilir. Bildirimi kolaydır Nums = Constants(ONE=1, PI=3.14159, DefaultWidth=100.0), Kullanımı basittir print 10 + Nums.PI, istisna Nums.PI = 22=> ValueError (..) içindeki sonuçları değiştirmeye çalışın.
ToolmakerSteve

108
Sadece değiştirmeyin. günümü yaptın
Hi-Angel

89
"Sadece değiştirmeyin" hiç yardımcı olmaz. Soruyu cevaplamıyor ve kaldırılmasını öneriyorum.
Bartek Banachewicz

354

constDiğer dillerde olduğu gibi bir anahtar kelime yoktur , ancak verileri okumak için "alıcı işlevi" olan bir Özellik oluşturmak mümkündür , ancak verileri yeniden yazmak için "ayarlayıcı işlevi" yoktur . Bu esas olarak tanımlayıcının değiştirilmesini önler.

Class özelliğini kullanan alternatif bir uygulama:

Kodun sabitleri merak eden bir okuyucu için çok kolay olmadığını unutmayın. Aşağıdaki açıklamaya bakın

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

Kod Açıklaması:

  1. constantİfadeyi alan bir işlevi tanımlayın ve bunu bir "alıcı" oluşturmak için kullanır - yalnızca ifadenin değerini döndüren bir işlev.
  2. Setter işlevi TypeError değerini artırır, böylece salt okunur olur
  3. Kullanım constantbiz sadece hızlı salt okunur özelliklerini tanımlamak için bir dekorasyon olarak oluşturulan işlevi.

Ve daha eski moda bir şekilde:

(Kod oldukça zor, daha fazla açıklama aşağıda)

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

@Apply dekoratör kullanımdan kaldırılmış gibi görünüyor.

  1. FOO tanımlayıcısını tanımlamak için, firs iki işlevi tanımlar (fset, fget - isimler seçimimde).
  2. Ardından, property"set" veya "get" olabilecek bir nesne oluşturmak için yerleşik işlevi kullanın.
  3. Not şapka propertyişlevin ilk iki parametre adlandırılır fsetve fget.
  4. Bu alıcıları kendi alıcı ve ayarlayıcımız için seçtiğimiz gerçeği kullanın ve parametreleri propertyişleve iletmek için o kapsamın tüm yerel tanımlarına uygulanan ** (çift yıldız) kullanarak bir anahtar kelime sözlüğü oluşturun

11
Belgelere dayanarak AttributeErrorve TypeErrorben kaldırdı istisna ben adlandırma öneriyoruz yeni hata, olması gerektiğini düşünüyorum ConstantErrorveya bir alt sınıfıdır onun gibi bir şey, TypeError. Dokümanlardaki beni düşündüren bölüm: docs.python.org/2/library/exceptions.html
ArtOfWarfare

3
Bu kod beni şaşırttı. Neden FOO () ve BAR () yöntemleri fontu bağımsız değişken olarak kendini gösterir? IDE'm kırmızı renkteki köşeli parantezlerin altını çiziyor ("derleme" hatası). Ben içine koymak için yorgun ama sonra bir hata alıyorum.
user3770060

10
Bu uzunluklara gitmek, python dilinde açık bir eksikliği özetliyor. Neden bunu Python 3'e ekleme gereğini hissetmediler. Kimsenin önermediğine inanamıyorum ve sadece bazı komitelerin arkasındaki mantığı göremiyorum, sabitler? Hayır.'
Andrew S

8
Ve çözüm hala kararlı bir python programcısı tarafındanCONST.__dict__['FOO'] = 7
pppery

11
@OscarSmith, 'kendi kendini belgeleyen kod' tasarımını geliştireceğini düşünüyorum. Kodda bazı değerlerin değiştirilemeyeceği açık hale getirildiğinde, tüm kaynak kodlarını okumaktan ve bazı değerlerin asla değişmediğini fark etmekten daha kolaydır. Ayrıca, birisinin sabit olması gereken bir değeri değiştirme olasılığını da engeller. Unutmayın: açık, örtük olmaktan iyidir.
Gabriel

112

Python'da, bir şeyi zorlamak yerine, insanlar adlandırma kurallarını örneğin __methodözel yöntemler ve _methodkorumalı yöntemler için kullanırlar .

Aynı şekilde, sabiti tüm büyük harflerle olduğu gibi açıklayabilirsiniz.

MY_CONSTANT = "one"

Bu sabitin asla değişmemesini istiyorsanız, özellik erişimine bağlanabilir ve püf noktaları yapabilirsiniz, ancak daha basit bir yaklaşım bir işlevi bildirmektir.

def MY_CONSTANT():
    return "one"

Tek sorun MY_CONSTANT () yapmak zorunda olduğunuz her yerde, ama yine MY_CONSTANT = "one"python (genellikle) doğru yoludur.

Sabitler oluşturmak için namedtuple öğesini de kullanabilirsiniz :

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

18
Bunu yapmak def MY_CONSTANT(): return "one", daha sonra kodda bulunan MY_CONSTANT = "two"(veya işlevi yeniden belirten) birini durdurmaz .
Matthew Schinckel

6
@MatthewSchinckel konvansiyonla ilgili, ayrıca MY_CONSTANT'ın değiştirilmesi MY_CONSTANT () kullanımını değiştirmeyecek, ancak hata atacak ve eğer bir şey değiştirebilirseniz, hiçbir akıllı hile sizi koruyamaz.
Anurag Uniyal

3
Adlandırılmış üçlü yaklaşımı getirdiğiniz için teşekkür ederiz. Kesinlikle yenilikçi. Burada ayrıca "yorumumu" da bulabilirsiniz .
RayLuo

@MatthewSchinckel Python'da HERŞEYİ yeniden tanımlayabilirsiniz, bu yüzden bu gerçekten iyi bir nokta değil.
cslotty

@MatthewSchinckel Fikir yazmak değil , sabit olarak MY_CONSTANT = MY_CONSTANT()kullanmaktır MY_CONSTANT(). Tabii ki, bu. Ancak bu iyi ve python prensibi ile uyumludur "Hepimiz yetişkiniz" - yani geliştiricinin, iyi nedenleri olduğunda ve ne yaptıklarını bildiğinde bir kuralı geçersiz kılmaya karar vermesi nadiren yasaktır .
jonathan.scholbach

69

Kısa bir süre önce, anlamlı hata mesajlarını otomatik olarak yükselten ve üzerinden erişimi engelleyen çok kısa bir güncelleme buldum __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'

Kendimizi bir örnek yapmak olarak tanımlıyoruz ve daha sonra ek özellik eklenemediğinden emin olmak için yuvalar kullanıyoruz. Bu, __dict__erişim yolunu da kaldırır . Tabii ki, tüm nesne hala yeniden tanımlanabilir.

Düzenle - Orijinal çözüm

Muhtemelen burada bir numaram yok, ama bu benim için işe yarıyor gibi görünüyor:

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

Örneği oluşturmak, sihirli __setattr__yöntemin devreye girmesine ve FOOdeğişkeni ayarlama girişimlerine engel olmasına izin verir . İsterseniz buraya bir istisna atabilirsiniz. Örneği sınıf adı üzerinde örneklemek, doğrudan sınıf üzerinden erişimi engeller.

Bir değer için tam bir acıdır, ancak CONSTnesnenize çok şey ekleyebilirsiniz . Bir üst sınıfa sahip olmak, sınıf adı da biraz kaba görünüyor, ama bence genel olarak oldukça özlü.


11
Bu en iyi ve en açık cevaptır, çünkü en az "mekanizmaya", ancak en fazla işlevselliğe sahiptir. Bir istisna oluşturmak önemli ... bir seçenek değil.
Erik Aronesty

Otomatik olarak anlamlı hatalar üreten, ancak aynı stilde çok daha kısa bir rota yaptım. Karşılaştırma için orijinal fikri burada bıraktım.
Jon Betts

Ne yazık ki hala bu CONST.önek gerekiyor . Ayrıca çok modüllü durumlarda bu karmaşık olacaktır.
Alfe

1
Ben tipik olarak bu durumda yine de bazı ilgili paketler halinde sabitleri grup istiyorum (bir dev CONST nesnesi yerine), bu yüzden muhtemelen böyle kötü bir şey değil düşünüyorum.
Jon Betts

Bu cevap neden bu kadar aşağıda ?! __slots__Solüsyon çok zarif ve etkilidir. Okuduğum her şeyden, bu Python'da sabitler oluşturmaya yaklaşıyor. Çok teşekkür ederim. Ve ilgilenen herkes için, burada__slots__ sihrin parlak ve derinlemesine bir açıklaması var .
JohnGalt

34

Python'un sabitleri yok.

Belki de en kolay alternatif, bunun için bir işlev tanımlamaktır:

def MY_CONSTANT():
    return 42

MY_CONSTANT() artık bir sabitin tüm fonksiyonlarına sahiptir (artı bazı can sıkıcı parantezler).


1
Sadece bu öneriyi eklemek istedim ama neyse ki düşük puanlı cevaplara geçtim. Umarım daha da ileri sürülecek ve bir sabitin tüm işlevselliğine sahip olduğunu ve çok basit ve anlaşılır olduğunu tamamen kabul ediyorum. Tüm sofistike çözümlerde kazan plakası miktarına bakıldığında, parantezleri nispeten rahatsız edici buluyorum.
yaccob

1
Bu en basit cevaptır, ancak bazı ek yükleri olduğu ve geri dönüş değerini değiştiren salakları durdurmayacağına dikkat edilmelidir. Sadece kodun satır değiştirerek kaynağı değiştirmesini
önleyecektir

@MrMesees dönüş değerini değiştiriyor mu? Kaynağı düzenlemek mi demek istediniz? Ancak bundan sabitlerin (sabit constexpr) gerçek sabit sabitler olduğu C ++ 'da bile korunmazsınız .
Ruslan

@Ruslan, python'un bir constexpr'sine sahip olmadığı için, dış bir bağlama döndükten sonra düzenlenmekte olan değerin durmayacağıydı. Bu örnekte donmuş durumu uygulamak için 42'ye hiçbir şey yapılmamıştır.
MrMesees

20

En iyi iki yanıta ek olarak (sadece UPPERCASE adlı değişkenleri kullanın veya değerleri salt okunur yapmak için özellikleri kullanın), adlandırılmış sabitleri uygulamak için metasınıfları kullanmanın mümkün olduğunu belirtmek isterim . GitHub'daki metasınıfları kullanarak çok basit bir çözüm sağlarım. Değerlerin türleri / adları hakkında daha bilgilendirici olmasını istiyorsanız yardımcı olabilir:

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

Bu biraz daha gelişmiş Python, ancak yine de kullanımı çok kolay ve kullanışlı. (Modül, sabitlerin salt okunur olması da dahil olmak üzere daha fazla özelliğine sahiptir, bkz. README.)

Çeşitli depolarda yüzen benzer çözümler var, ancak bildiklerime göre ya sabitlerden beklediğim temel özelliklerden birine sahip değiller (sabit olmak ya da keyfi tip olmak gibi) ya da ezoterik özelliklere sahipler. genel olarak daha az uygulanabilir olmasını sağlayın. Ama YMMV, geri bildirim için minnettar olurum. :-)


3
GitHub'daki uygulamanızı beğendim. Ters arama işlevini uygulayan temel bir sınıf yazmaya neredeyse hazırdım, ama bunu ve daha fazlasını yaptığınızı görüyorum!
Kerr

Teşekkürler @Kerr, aldığım ve beni mutlu ettiğim ilk geri bildirim. :-)
hans_meine

Muhteşem. Sadece denedim. Bu seçenek olarak güzel. Ben sadece okuma yönünü yeterli umurumda değil karar vermiş olsa da, sadece yapmak yerine bunu kullanmak için def enum(**enums): return type('Enum', (), enums). Numbers = enum(ONE=1, TWO=2, THREE='three'), stackoverflow.com/a/1695250/199364 uyarınca , "Önceki sürümlerde ..." bölümü
ToolmakerSteve

19

Özellikler, sabitler oluşturmanın bir yoludur. Bunu bir getter özelliği bildirerek ancak ayarlayıcıyı yok sayarak yapabilirsiniz. Örneğin:

class MyFinalProperty(object):

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

Python özelliklerini kullanmanın daha fazla yolunu bulmak için yazdığım bir makaleye göz atabilirsiniz .


Değerli çözüm altında. Ben sadece bu sayfayı (bu cevabı değil) bulduktan sonra uyguladım ve henüz değilse eklemek için geri döndüm. Bu cevabın yararlılığının altını çizmek istedim.
Marc

18

Düzenleme: Python 3 için örnek kod eklendi

Not: Bu diğer cevap , aşağıdakine benzer çok daha eksiksiz bir uygulama sağladığı görülmektedir (daha fazla özellik ile).

İlk önce bir metasınıf yapın :

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

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

Bu, statik özelliklerinin değiştirilmesini önler. Sonra bu metasınıfı kullanan başka bir sınıf yapın:

class Const(object):
    __metaclass__ = MetaConst

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

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

Veya Python 3 kullanıyorsanız:

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

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

Bu, örnek sahne aksesuarlarının değiştirilmesini engellemelidir. Kullanmak için devralın:

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

Şimdi doğrudan veya bir örnek aracılığıyla erişilen sahne sabit olmalıdır:

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

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

İşte yukarıda eylem örneği. İşte Python 3 için başka bir örnek.


10

Java'da statik bir son değişkenle (Java "sabiti") aynı şekilde çalışan bir sabit oluşturmak için adlandırılmış bir çözümü geçici çözüm olarak kullanabilirsiniz. Geçici çözümler ilerledikçe bir nevi zariftir. (Daha zarif bir yaklaşım, Python dilini basitçe iyileştirmek olacaktır - ne tür bir dil yeniden tanımlamanıza izin verir math.pi? - Ama araştırıyorum .)

(Bunu yazarken, adlandırılmış bu soruya başka bir cevap daha fark ediyorum, ancak burada devam edeceğim, çünkü adlandırılmış bir dosya oluşturmaya gerek olmadığı için Java'da beklediğinize daha yakından benzeyen bir sözdizimi göstereceğim. tip yapmanız namedtuple güçleri olarak.)

Örneğinizin ardından, Java'da bir sınıfın içindeki sabiti tanımlamamız gerektiğini hatırlayacaksınız ; çünkü bir sınıf adından bahsetmedin, diyelim Foo. İşte Java sınıfı:

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

İşte eşdeğer Python.

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

Buraya eklemek istediğim önemli nokta, ayrı bir Footüre ihtiyacınız olmaması ("anonim adlı bir grup" çok hoş olurdu, bu bir oksimoron gibi görünse bile), bu yüzden adlandırılmış grubumuzu adlandırıyoruz _Fooki umarım ithalat modülü kaçış.

Buradaki ikinci nokta derhal nametuple'in bir örneğini oluşturup onu çağırmamızdır Foo; bunu ayrı bir adımda yapmaya gerek yoktur (istemiyorsanız). Artık Java ile yapabileceklerinizi yapabilirsiniz:

>>> Foo.CONST_NAME
'Name'

Ancak atayamazsınız:

>>> Foo.CONST_NAME = 'bar'

AttributeError: can't set attribute

Teşekkür: Adlandırılmış üçlü yaklaşımı icat ettiğimi sanıyordum, ama sonra başka birinin benzer (daha az kompakt olmasına rağmen) bir cevap verdiğini görüyorum. Sonra Python "adlandırılmış tuples" nedir fark ettim ? Bu sys.version_info, şimdi adlandırılmış bir dizi olduğuna dikkat çekiyor, belki de Python standart kütüphanesi bu fikri çok daha önce ortaya koymuştu.

Ne yazık ki (bu hala Python olarak), tüm Fooödevi tamamen silebileceğinizi unutmayın :

>>> Foo = 'bar'

(Facepalm)

Ama en azından Foo.CONST_NAMEdeğerin değiştirilmesini engelliyoruz ve bu hiç yoktan iyidir. İyi şanslar.


Adlandırılmış üçlü yaklaşımı getirdiğiniz için teşekkür ederiz. Kesinlikle yenilikçi. Burada ayrıca "yorumumu" da bulabilirsiniz .
RayLuo

10

PEP 591 'nihai' niteleyiciye sahiptir. Uygulama tip denetleyicisine bağlıdır.

Böylece şunları yapabilirsiniz:

MY_CONSTANT: Final = 12407

Not: Final anahtar kelime yalnızca Python 3.8 sürümü için geçerlidir


9

Burada, salt okunur (sabit) özniteliklere sahip örnekler oluşturan "Sabitler" sınıfının bir uygulaması verilmiştir. Örneğin Nums.PI, olarak başlatılmış 3.14159ve Nums.PI = 22bir istisna yaratan bir değer elde etmek için kullanabilir .

# ---------- 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

Başlangıç ​​noktası olarak kullandığım @MikeGraham'ın FrozenDict'ı sayesinde . Değişti, yani Nums['ONE']kullanım sözdizimi yerine Nums.ONE.

Ve @ Raufio'nun cevabı sayesinde, __ setattr __ 'i geçersiz kılma fikri.

Veya daha fazla işlevselliğe sahip bir uygulama için GitHub'daki @Hans_meine adlı adlı kullanıcının_kabzlarına bakın


2
Python yetişkinlere rıza gösterme dilidir. Böyle bir şeye karşı koruma yoktur. Nums._d['PI'] = 22 Dilin kendisi, şeyleri değişmez olarak işaretlemek için herhangi bir yol sağlamadığına inanıyorum.
Ajay M

8

Bir demet teknik olarak sabit olarak nitelendirilir, çünkü bir demet değerlerinden birini değiştirmeye çalışırsanız bir hata oluşturur. Bir değeri olan bir tuple bildirmek istiyorsanız, tek değerinden sonra virgül koyun, şöyle:

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

Bu değişkenin değerini kontrol etmek için aşağıdakine benzer bir şey kullanın:

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

Bu değeri değiştirmeye çalışırsanız bir hata ortaya çıkar.


7

__setattr__Temel nesne sınıfının yöntemini geçersiz kılan bir sınıf yapmak ve bu sabitleri ile sarın, python 2.7 kullanıyorum unutmayın:

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)

Bir dizeyi kaydırmak için:

>>> 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'

Oldukça basit, ancak sabitlerinizi sabit olmayan bir nesneyle (constObj.value kullanmadan) kullanmak istediğiniz gibi kullanmak istiyorsanız, biraz daha yoğun olacaktır. Bunun sorunlara neden olması mümkündür, bu nedenle .valuesabitleri ile işlemler yaptığınızı göstermek ve bilmek en iyisi olabilir (belki de en 'pythonic' yolu değil).


+ 1 ilginç bir yaklaşım için. Daha önce verilen cevaplar kadar temiz olmasa da. Ve daha önce önerilen en basit çözümü bile bu cevaptan def ONE(): return 1daha kolaydır . ONE()ONE.value
ToolmakerSteve

7

Maalesef Python'un henüz sabiti yok ve utanç verici. ES6, JavaScript'e zaten destek sabitleri eklemiştir ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const ), çünkü herhangi bir programlama dilinde çok yararlı bir şeydir. Python topluluğundaki diğer yanıtlarda yanıtlandığı gibi, kullanıcı büyük harf değişkeni sabit olarak kullanılır, ancak koddaki keyfi hatalara karşı koruma sağlamaz. İsterseniz, bir sonraki dosya gibi yararlı bir tek çözüm bulabilirsiniz (bkz. Docstrings nasıl kullanılır).

dosya sabitleri.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()

Bu yeterli değilse, tam test çantasına bakın.

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

Avantajları: 1. Tüm proje için tüm sabitlere erişim 2. Sabit değerleri için sıkı kontrol

Eksiklikler: 1. Özel türler ve 'dikte' türü için desteklenmez

Notlar:

  1. Python3.4 ve Python3.5 ile test edildi (Bunun için 'toks' kullanıyorum)

  2. Test ortamı:

.

$ 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

Sözlükleri otomatik olarak adlandırılmış gruplara dönüştürerek bunu biraz geliştirebilirsiniz
Peter Schorn

6

"Sabitler" bildirmenin Pythonic yöntemi temelde modül düzeyinde bir değişkendir:

RED = 1
GREEN = 2
BLUE = 3

Ve sonra sınıflarınızı veya işlevlerinizi yazın. Sabitler neredeyse her zaman tamsayı olduğundan ve Python'da değişmez olduklarından, bunu değiştirme şansınız çok azdır.

Tabii ki, açıkça belirlediyseniz RED = 2.


21
Evet, ancak "açıkça" ayarlama yeteneğini engellemek , RED = 2değişken adını "sabit" olarak bildirmenin tüm avantajıdır (diğer dillerde)!
ToolmakerSteve

6
Bunu engellemekten faydalanır mıydınız? Const ile ilgili en faydalı şey genellikle Python'da bir şey olmayan derleyici optimizasyonlarıdır. Bir şeyin sabit olmasını ister misiniz? Sadece değiştirmeyin. Başka birini değiştirmekten endişe ediyorsanız, onu kendi kapsamının dışına koyabilir veya sadece biri değiştiriyorsa, bu onların sorunu olduğunu ve bununla başa çıkmaları gerektiğini anlayabilirsiniz.
Kevin

@Kevin: " Would yararı ... alacağı , yararına" staticbir sınıfın tüm örnekleri için değerin tek depolama alanına sahip olması? Statik / sınıf değişkeni bildirme olasılığı olmadığı sürece.
dakika

8
Kök sorun, bazılarının onu bir gerçek kaynağı olan, değiştirilemeyen bir değer olarak görebilmesi ve onu sihirli değerler (Python'da çok fazla gördüğüm) yerine kodları boyunca gerçeğin kaynağı olarak kullanabilmesidir. - ve diğerleri bunu istediği zaman değiştirmelerine izin verilen bir şey olarak görebilir. Birisi genel bir değişkeni değiştirdiğinde ve nerede değiştiğini söyleyemediğinizde ve uygulama "kırmızı" yerine RED = "mavi" olduğu için çöktüğünde, çok basit bir şekilde çözülmüş olan tamamen gereksiz bir sorun ortaya çıkarırsınız ve evrensel olarak anlaşılmaktadır.
Dagrooms

5

Bir tanımlayıcı nesne oluşturabiliriz.

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

1) Örnek düzeyinde sabitlerle çalışmak istersek:

class A:
  NULL = Constant()
  NUM = Constant(0xFF)

class B:
  NAME = Constant('bar')
  LISTA = Constant([0,1,'INFINITY'])

>>> obj=A()
>>> print(obj.NUM)  #=> 255
>>> obj.NUM =100

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: You can't change a constant

2) yalnızca sınıf düzeyinde sabitler oluşturmak isteseydik, sabitlerimiz (tanımlayıcı nesnelerimiz) için bir kap görevi gören bir metasınıf kullanabilirdik; inen tüm sınıflar, değişme riski olmadan sabitlerimizi (tanımlayıcı nesnelerimiz) miras alacaktır.

# metaclass of my class Foo
class FooMeta(type): pass

# class Foo
class Foo(metaclass=FooMeta): pass

# I create constants in my metaclass
FooMeta.NUM = Constant(0xff)
FooMeta.NAME = Constant('FOO')

>>> Foo.NUM   #=> 255
>>> Foo.NAME  #=> 'FOO'
>>> Foo.NUM = 0 #=> ValueError: You can't change a constant

Foo'nun bir alt sınıfını oluşturursam, bu sınıf değişme olasılığı olmadan sabiti devralır

class Bar(Foo): pass

>>> Bar.NUM  #=> 255
>>> Bar.NUM = 0  #=> ValueError: You can't change a constant

4

Python sözlükleri değiştirilebilir, bu nedenle sabitleri bildirmenin iyi bir yolu gibi görünmüyor:

>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}

4

Sabitleri istiyorsanız ve değerlerini umursamıyorsanız bir püf noktası:

Sadece boş sınıfları tanımlayın.

Örneğin:

class RED: 
    pass
class BLUE: 
    pass

4

Python'da sabit, basitçe tüm büyük harflerde bir adı olan ve alt çizgi karakteriyle ayrılmış kelimeler içeren bir değişkendir,

Örneğin

DAYS_IN_WEEK = 7

Değeri değiştirebileceğiniz gibi, değer değiştirilebilir. Ama isminin kurallarının size sabit olduğunu söyleyince, neden? Sonuçta, bu sizin programınız!

Bu, python boyunca uygulanan yaklaşımdır. privateAynı nedenden ötürü anahtar kelime yok . Adın önüne bir alt çizgi ekleyin ve bunun özel olması gerektiğini bilirsiniz. Kod, bir programcının özel anahtar kelimeyi yine de kaldırabileceği gibi ... kuralı kırabilir.

Python bir const anahtar kelime ekleyebilirdi ... ama bir programcı anahtar kelimeyi kaldırabilir ve sonra isterse sabiti değiştirebilir, ama neden bunu yapsın? Kuralı çiğnemek istiyorsanız, kuralı yine de değiştirebilirsiniz. Ama eğer isim niyeti açıklığa kavuşturursa, kuralı çiğnemeye ne dersin?

Belki de değerde bir değişiklik yapmanın mantıklı olduğu bazı birim testler vardır? Gerçek dünyada olmasına rağmen 8 günlük bir hafta için neler olduğunu görmek için haftadaki gün sayısı değiştirilemez. Eğer bu tek bir durum varsa, dil bir istisna yapmayı durdurduysa, kuralı kırmanız gerekir ... o zaman uygulamada sabit olmasına rağmen, bunu sabit olarak bildirmeyi bırakmanız gerekir ve sadece değiştirilirse ne olduğunu gören bir test durumu.

Tüm büyük harf adı size sabit olması gerektiğini söyler. İşte önemli olan da budur. Zaten kod değiştirme zorunluluğuna sahip bir dil değil zaten değiştirme gücünüz var.

Python'un felsefesi budur.


4

Bunu yapmanın mükemmel bir yolu yok. Anladığım kadarıyla, çoğu programcı tanımlayıcıyı büyük harfe çevirecektir, bu nedenle PI = 3.142'nin bir sabit olduğu kolayca anlaşılabilir.

Öte yandan, aslında sabit gibi davranan bir şey istiyorsanız, onu bulacağınızdan emin değilim. Yaptığınız herhangi bir şeyle "sabit" i düzenlemenin her zaman bir yolu olacaktır, bu yüzden gerçekten bir sabit olmayacaktır. Çok basit ve kirli bir örnek:

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

Bu PHP tarzı bir sabit yapacak gibi görünüyor.

Gerçekte, birinin değerini değiştirmesi için gereken tek şey şudur:

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

Bu, burada bulacağınız diğer tüm çözümler için aynıdır - bir sınıf oluşturan ve set öznitelik yöntemini yeniden tanımlayan akıllı çözümler bile - her zaman onların etrafında bir yol olacaktır. Python böyle.

Benim tavsiyem sadece tüm zorluklardan kaçınmak ve sadece tanımlayıcılarınızı büyük harfle kullanmaktır. Gerçekten uygun bir sabit olmazdı ama yine de hiçbir şey olmazdı.


4

Namedtuple ile bunu yapmanın daha temiz bir yolu var:

from collections import namedtuple


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

Kullanım Örneği

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

Tam olarak bu yaklaşımla sabitlerinizi adlandırabilirsiniz.


Bunu okuyan herkes için, lütfen değişebilir bir nesneyi bu sabitlerden biri olarak ayarlarsanız, herkesin kendi iç değerini değiştirebileceğini unutmayın. örneğin, bar = [1, 2, 3] 'e izin verirseniz, şu şekilde yapabilirsiniz: CONSTS.bar [1] =' a 've reddedilmeyecek. Bu yüzden dikkatli olun.
Juan Ignacio Sánchez

Sadece eğlence için yaptığım bu hacky yöntemi yerine, Python'un özellik dekoratörünü kullanmanızı tavsiye ederim.
Juan Ignacio Sánchez

4

Belki de pconst kütüphanesi size yardımcı olacaktır ( github ).

$ pip install pconst

from pconst import const
const.APPLE_PRICE = 100
const.APPLE_PRICE = 200

[Out] Constant value of "APPLE_PRICE" is not editable.


3

StringVar veya IntVar, vb. Kullanabilirsiniz, sabitiniz const_val

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

def reverse(*args):
    const_val.set(val)

2

Sen ile yapabilirsiniz collections.namedtupleve itertools:

import collections
import itertools
def Constants(Name, *Args, **Kwargs):
  t = collections.namedtuple(Name, itertools.chain(Args, Kwargs.keys()))
  return t(*itertools.chain(Args, Kwargs.values()))

>>> myConstants = Constants('MyConstants', 'One', 'Two', Three = 'Four')
>>> print myConstants.One
One
>>> print myConstants.Two
Two
>>> print myConstants.Three
Four
>>> myConstants.One = 'Two'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

2

(Bu paragraf bu cevaplar üzerine bir yorumdur olması gerekiyordu burada ve orada belirtilen,namedtuple ama o kadar, işte gidiyor, Bir yoruma uyum olamayacak kadar uzun oluyor.)

Yukarıda adı geçen adlandırılmış yaklaşım kesinlikle yenilikçi. Tamlık uğruna , resmi belgelerinin NamedTuple bölümünün sonunda şunu okur:

numaralandırılmış sabitler adlandırılmış gruplarla uygulanabilir, ancak basit bir sınıf bildirimi kullanmak daha basit ve daha verimlidir:

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

Başka bir deyişle, resmi belge türü, salt okunur davranışı uygulamak yerine pratik bir yöntem kullanmayı tercih eder. Sanırım Python Zen başka bir örnek olur :

Basit, karmaşık olmaktan iyidir.

pratiklik saflığı yener.


2

Burada, mevcut cevapların bazılarını iyileştirmek için oluşturduğum deyimlerin bir koleksiyonu.

Sabit kullanımının pitonik olmadığını biliyorum ve bunu evde yapmamalısınız!

Ancak, Python çok dinamik bir dildir! Bu forum, sabit gibi görünen ve hissedilen yapıların oluşturulmasının nasıl mümkün olduğunu göstermektedir. Bu cevabın ana amacı, dil tarafından neyin ifade edilebileceğini araştırmaktır.

Lütfen bana karşı çok sert olma :-).

Daha fazla ayrıntı için bu deyimler hakkında bir eşlik blogu yazdım .

Bu yazıda, değerlere (değişmez veya başka türlü) sabit bir referansa sabit bir değişken çağıracağım. Dahası, bir değişkenin bir istemci kodunun değerlerini güncelleyemediği değiştirilebilir bir nesneye başvurduğunda değişkenin donmuş bir değere sahip olduğunu söylüyorum.

Sabitler alanı (SpaceConstants)

Bu deyim, sabit değişkenlerin (SpaceConstants olarak adlandırılan bir ad alanı) neye benzediğini yaratır. Modül nesnelerinin kullanılmasını önlemek için Alex Martelli tarafından bir kod snippet'inin değiştirilmesi . Özellikle, çünkü içinde bir sınıf fabrika dediğimiz bu modifikasyon kullandığı SpaceConstants , bir sınıf olarak adlandırılan işlev SpaceConstants tanımlanır ve bunun bir örneği döndürülür.

Python'da stackoverflow'da ve aynı zamanda bir blog yazısında politika tabanlı bir tasarım görünümü uygulamak için sınıf fabrikasının kullanımını araştırdım .

def SpaceConstants():
    def setattr(self, name, value):
        if hasattr(self, name):
            raise AttributeError(
                "Cannot reassign members"
            )
        self.__dict__[name] = value
    cls = type('SpaceConstants', (), {
        '__setattr__': setattr
    })
    return cls()

sc = SpaceConstants()

print(sc.x) # raise "AttributeError: 'SpaceConstants' object has no attribute 'x'"
sc.x = 2 # bind attribute x
print(sc.x) # print "2"
sc.x = 3 # raise "AttributeError: Cannot reassign members"
sc.y = {'name': 'y', 'value': 2} # bind attribute y
print(sc.y) # print "{'name': 'y', 'value': 2}"
sc.y['name'] = 'yprime' # mutable object can be changed
print(sc.y) # print "{'name': 'yprime', 'value': 2}"
sc.y = {} # raise "AttributeError: Cannot reassign members"

Donmuş değerlerin boşluğu (SpaceFrozenValues)

Bu sonraki deyim, başvurulan değiştirilebilir nesnelerin dondurulduğu SpaceConstants'ın bir modifikasyonudur . Bu uygulama setattr ve getattr işlevleri arasında paylaşılan kapatma dediğim sömürür . Değişken nesnenin değeri kopyalanır ve paylaşılan önbellek işlevi içindeki tanımlanmış değişken önbellek tarafından başvurulur . Değişebilir bir nesnenin kapanma korumalı bir kopyasını dediğim şeyi oluşturur .

Bu deyimi kullanırken dikkatli olmalısınız çünkü getattr derin bir kopya yaparak önbellek değerini döndürür. Bu işlemin büyük nesneler üzerinde önemli bir performans etkisi olabilir!

from copy import deepcopy

def SpaceFrozenValues():
    cache = {}
    def setattr(self, name, value):
        nonlocal cache
        if name in cache:
            raise AttributeError(
                "Cannot reassign members"
            )
        cache[name] = deepcopy(value)
    def getattr(self, name):
        nonlocal cache
        if name not in cache:
            raise AttributeError(
                "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 x
print(fv.x) # print "2"
fv.x = 3 # raise "AttributeError: Cannot reassign members"
fv.y = {'name': 'y', 'value': 2} # bind attribute y
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y['name'] = 'yprime' # you can try to change mutable objects
print(fv.y) # print "{'name': 'y', 'value': 2}"
fv.y = {} # raise "AttributeError: Cannot reassign members"

Sabit bir alan (ConstantSpace)

Bu deyim, sabit değişkenlerin veya ConstantSpace'in değişmez bir ad alanıdır . Stackoverflow'daki inanılmaz basit Jon Betts'in cevabını bir sınıf fabrikasıyla birleştiriyor .

def ConstantSpace(**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 changed
print(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'"

Donmuş bir alan (FrozenSpace)

Bu deyim, dondurulmuş değişkenlerin veya FrozenSpace'in değişmez bir ad alanıdır . Oluşturulan FrozenSpace sınıfının kapatılmasıyla her değişkenin korumalı bir özellik haline getirilmesiyle önceki modelden türetilir .

from copy import deepcopy

def FreezeProperty(value):
    cache = deepcopy(value)
    return property(
        lambda self: deepcopy(cache)
    )

def FrozenSpace(**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 object
print(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'"

2

Python'da sabitler mevcut değildir, ancak bir değişkenin sabit olduğunu ve CONST_değişken adının başına eklenerek ve bir yorumda sabit olduğunu belirterek değiştirilmemesi gerektiğini belirtebilirsiniz :

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.

Alternatif olarak, sabit gibi davranan bir işlev oluşturabilirsiniz:

def CONST_daysInWeek():
    return 7;

1

Benim durumumda, sabit olmasını sağlamak istediğim birçok gerçek sayı içeren bir kripto kütüphanesinin uygulanması için değişmez bytearraylere ihtiyacım vardı.

Bu yanıt işe yarıyor, ancak bytearray elemanlarının yeniden atanması girişimi hata vermiyor.

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

Sabitler değişmez, ancak sabit bytearray ataması sessizce başarısız olur:

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

Daha güçlü, basit ve belki daha da 'pythonic' yaklaşım, memoryview nesnelerinin (<= python-2.6 içindeki tampon nesneler) kullanımını içerir.

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)

ConstArray öğe ataması 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

Python const için bir util lib yazıyorum: kkconst - pypi support str, int, float, datetime

const field örneği temel tür davranışını koruyacaktır.

Örneğin:

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

daha fazla detay kullanımı pypi url okuyabilirsiniz: pypi veya github


1

Bir sabiti bir numpy dizisine sarabilir, yalnızca yazdığını işaretleyebilir ve her zaman sıfır diziniyle çağırabilirsiniz.

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

elbette bu sadece numpy'nin içeriğini korur, "CONSTANT" değişkeninin kendisini değil; hala yapabilirsiniz:

CONSTANT = 'foo'

ve CONSTANTdeğişeceğini, ancak o hızla bir TypeError ilk kez atardıCONSTANT[0] sonra komut denir.

buna rağmen ... sanırım bir noktada bunu

CONSTANT = [1,2,3]

artık TypeError alamıyorsunuz. hmmmm ....

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.