2010-09-14 18 views
9

Onların programı başlatma kodu yalnızca bir kez ayarlanır bir şekilde küresel değişkenler (veya küresel kapsamlı değişkenler) kontrol ve bundan sonra onları kilitlemek istiyorum.Python'da bir nesneyi değiştirmeyi engelleyebilir miyim?

Küresel değişkenler için UPPER_CASE_VARIABLES kullanmak, ama yine değişken değiştirmek için değil emin bir şekilde sahip olmak istiyorum.

  • Python bu (veya benzer) özelliği sağlıyor mu?
  • nasıl küresel kapsamlı değişkenleri kontrol edebilirim?
+4

Bunu neden üzerine vakit geçiriyorsunuz? İnsanların Python kaynağınız var. Sadece değiştirebilirler. Neden "final" ve "sabit" ile uğraşalım? –

+1

Biliyorsunuz, bu çok amaçlı. Python beyleri, hepimiz yetişkiniz ve onlar gibi davranmalıyız. Peki neden erişimi yasaklıyorsunuz? Bir yetişkin gibi davranın ve bunları asla kodunuzda değiştirmeyin. Eğer başka bir programcı yaparsa, kod kırılırsa onun hatasıdır ve kimin suçlayacağını bulmak için bir VCS (varsayalım) var. – Boldewyn

+1

Ayrıca, denetlemek kolay bir şey. Herhangi bir "UPPER_CASE =" örneği bir hatadır çünkü birisi kuralları ihlal etti. –

cevap

11

ActiveState'nın oluşturulması sonra yeniden edilemez özelliklere sahip bir const modül oluşturmak için saygıdeğer Alex Martelli tarafından Constants in Python başlıklı bir tarifi vardır. Bu, — numaralı sürümler haricinde aradığınız şey gibi görünüyor, ancak özellik adının büyük harf olup olmadığını kontrol ederek eklenebilir. Tabii ki, bu belirlenen tarafından engellenebilir, ancak bu Python'un yolu — ve çoğu kişi tarafından "iyi bir şey" olarak kabul edilir. Ancak, insanların daha sonra sadece isimleri silin ve farklı değerlere ribaund onları geri ekleyebilirsiniz beri sözde bariz __delattr__ yöntemi ekleme rahatsız etmeyin önermek, biraz daha zorlaştırmak için.

Bu benim hakkında alıyorum budur:

# Put in const.py... 
# from http://code.activestate.com/recipes/65207-constants-in-python 
class _const: 
    class ConstError(TypeError): pass # base exception class 
    class ConstCaseError(ConstError): pass 

    def __setattr__(self, name, value): 
     if name in self.__dict__: 
      raise self.ConstError("Can't change const.%s" % name) 
     if not name.isupper(): 
      raise self.ConstCaseError('const name %r is not all uppercase' % name) 
     self.__dict__[name] = value 

# replace module entry in sys.modules[__name__] with instance of _const 
# (and create additional reference to module so it's not deleted -- 
# see Stack Overflow question: http://bit.ly/ff94g6) 
import sys 
_ref, sys.modules[__name__] = sys.modules[__name__], _const() 

if __name__ == '__main__': 
    import const # test this module... 

    try: 
     const.Answer = 42 # not OK, mixed-case attribute name 
    except const.ConstCaseError as exc: 
     print(exc) 
    else: # test failed - no ConstCaseError exception generated 
     raise RuntimeError("Mixed-case const names should't have been allowed!") 

    const.ANSWER = 42 # should be OK, all uppercase 

    try: 
     const.ANSWER = 17 # not OK, attempts to change defined constant 
    except const.ConstError as exc: 
     print(exc) 
    else: # test failed - no ConstError exception generated 
     raise RuntimeError("Shouldn't have been able to change const attribute!") 

Çıktı:

const name 'Answer' is not all uppercase 
Can't change const.ANSWER 
+0

Sadece bir açıklama: Yerel ad alanına böyle bir "sabit" aktarırsanız, daha uzun "sabit" değil. Yerel isim kolayca geri alınabilir. Ve sonuçta, modül nesnesi her zaman geri tepebilir. – lunaryorn

+0

@lunaryorn: Oldukça doğru. Tarif ayrıca "Python Yemek Kitabı, 2d ed" kısmında da yer alır ve Martelli, listenin değişebilir olması durumunda, bağlı olan değerin yine de değiştirilebileceğinden bahseder. Kitabın, değiştirilebilen nesneleri sarmasına ve salt okunur olmasını sağlayan başka bir tarifinden bahsetmesini engellemek için. Bu diğer tarifi “Kalıtsal Alternatif Olarak Delegasyon” başlıklı ve Tartışma bölümünde çok fazla materyal var - cevabımda koymak için uygun olacağını düşündüğümden daha fazla - oraya gitmedim ... – martineau

+0

'object .__ setattr __ (const, 'this_is_not_a_costant', 88)' geçersiz bir sabiti ayarlamak veya bir sabiti yeniden tanımlamak için çalışacaktır. Benzer bir numara, 'object_ setattr__' (' class o (object): pass' sonra 'object .__ dict __ ['__ class __'] .__ set __ (const, o) kullanılmadan uygulanabilen' __class__' modifikasyonu kullanılarak da kullanılabilir.) ') sonra sıradan bir sınıf gibi nitelikler ayarlayabilirsiniz. – ppperry

2

Genel değişkenlerinizi bir nesneye sarın ve object .__ setattr__ yöntemini geçersiz kılabilirsiniz. Daha önceden ayarlanmış olan özellikleri ayarlamayı önleyebilirsiniz. Bununla birlikte, bu, referans olarak geçirilen karmaşık nesnelerle ilgilenmez. Değiştirilemediğinden kesinlikle emin olmak için bu nesnelerin sığ/derin kopyalarını yapmanız gerekir. Yeni stil sınıfları kullanıyorsanız, kopyaları oluşturmak için object .__ getattribute __ (self, name) geçersiz kılabilirsiniz.

class State(object): 
    def __init__(self): 
     pass 

    def __setattr__(self, name, value): 
     if name not in self.__dict__: 
      self.__dict__[name] = value 

** Birisi kodumu kırmak için gerçekten çok uğraşırsa çok endişelenmem. __setattr__ 'ın (özellikle bir istisna atarsanız), yalnızca Devlet'in amacının okunacak kodla oynayan kişiyi uyarması için yeterli olduğunu düşünüyorum. Eğer birisi hala devleti değiştirmeye ihtiyaç duyuyorsa, karşılaştıkları tanımsız davranışlar benim hatam değil.

+1

Ve birisinin nesnenin üzerine yazmasını engelleyen nedir? – mikerobi

+0

İyi nokta: P. Sanırım yapılabilecek fazla bir şey yok mu? Belki bir singleton? – GWW

+4

Her zaman birileri Python'da (veya diğer dinamik dillerdeki) sabitleri, özel üyeleri, aday tipi denetimi, vb ... öykünmeye çalıştığında, başarısız olur. İnsanlar ne zaman öğrenecek? (Bir singleton sınıfı, daha kolay bir şekilde yeniden tanımlanabilir) – delnan

6

Python çok açık bir dildir ve bir final anahtar kelime içermiyor. Python size bir şeyler yapma özgürlüğü verir ve işlerin nasıl yürüdüğünü bildiğinizi varsayar. Bu nedenle, kodunuzu kullanan kişilerin, kodda rastgele bir noktada SOME_CONSTANT numaralı değere bir değer atanmaması gerektiğini bildiği varsayılır.

Gerçekten, bir alıcı işlevi içinde sabit çevreleyebileceğim istiyorum yoksa

.

def getConstant() 
    return "SOME_VALUE" 
+5

'getConstant = lambda: new_value' yapmak hala mümkündür (ve sadece marjinal olarak daha karmaşık). "ALL_CAPS", olması gereken sabitlerin konması olduğundan, buna bağlı kalmalısınız. – delnan

İlgili konular