2010-09-14 85 views
9

我想控制全局變量(或全局作用域變量),它們只能在程序初始化代碼中設置一次,並在之後鎖定它們。我可以阻止修改Python中的對象嗎?

我對全局變量使用UPPER_CASE_VARIABLES,但是我想有一個確定的方法,不要改變變量。

  • python是否提供該功能(或類似功能)?
  • 如何控制全局範圍的變量?
+4

爲什麼你對這個花時間?人們有你的Python來源。他們可以改變它。爲什麼要圍繞「最終」和「不變」? – 2010-09-14 20:09:06

+1

你知道,這是故意的。 Python傢伙認爲,我們都是成年人,應該像個人一樣行事。那麼爲什麼要禁止訪問呢?像大人一樣行事,只是從不改變他們的代碼。如果另一位程序員這樣做,這是他的錯,如果代碼被破壞了,並且你有一個VCS來找出責怪誰(我認爲)。 – Boldewyn 2010-09-14 20:31:58

+1

此外,審計很容易。任何「UPPER_CASE ='的實例都是錯誤的,因爲有人違反了規則。 – 2010-09-15 02:33:05

回答

11

ActiveState的具有標題由古老Alex MartelliConstants in Python用於與不能創建之後被反彈的屬性創建const模塊的配方。這聽起來像你正在尋找的東西,除了—,但可以通過檢查屬性名稱是否全部是大寫來添加。

當然,這可以被確定的迴避,但這是Python的方式—,被認爲是大多數人的「好東西」。但是,爲了讓它更難一些,我建議你不要加入所謂的明顯的__delattr__方法,因爲人們可以刪除名稱,然後將回彈添加到不同的值。

這是我帶一下:

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

輸出:

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

只是一句話:如果您將一個這樣的「常量」導入到本地名稱空間中,它不再是「常量」。本地名稱很容易被反彈。畢竟,模塊對象總是可以被反彈。 – lunaryorn 2010-09-15 08:51:46

+0

@ lunaryorn:確實如此。該配方也出現在「Python Cookbook,第二版」中,Martelli提到了這個事實,即如果綁定的值是可變的,例如列表,它仍然可以被改變。爲了防止他在本書中提到另一個允許包裝可變對象並使其變爲只讀的配方。這個另一個配方的標題是「自動委派代替繼承」,討論部分有很多材料 - 比我認爲適合我的答案 - 所以我沒有去那裏...... – martineau 2010-09-15 13:10:13

+0

'object .__ setattr __(const,'this_is_not_a_costant',88)'將會設置一個無效常量或者重新定義一個常量。類似的技巧也可以使用'__class__'修改,它可以在不使用'object .__ setattr__'('class o(object):pass'後面跟着'object .__ dict __ ['__ class __'] .__ set __(const,o )'),之後可以像普通的類一樣設置屬性。 – ppperry 2016-05-30 19:02:54

2

你可以將你的全局變量包裝在一個對象中並覆蓋對象.__ setattr__方法。然後您可以防止設置已經設置的屬性。但是,這並不涉及通過引用傳遞的複雜對象。您需要製作這些對象的淺/深拷貝,以確保它們不能被修改。如果你正在使用新的風格類,你可以重寫object .__ getattribute __(self,name)來創建副本。

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

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

**我通常不用擔心這麼多,如果有人要真的很難打破我的代碼。我發現覆蓋__setattr__就足夠了(特別是如果你拋出一個異常)來警告誰在玩代碼,只有國家的目標是隻讀的。如果有人仍然覺得需要修改狀態,那麼他們遇到的不確定行爲不是我的錯。

+1

什麼會阻止某人覆蓋該對象? – mikerobi 2010-09-14 18:19:40

+0

好點:P。我想沒有太多可以做的事情?也許是一個單身人士? – GWW 2010-09-14 18:21:30

+4

每當有人試圖模仿Python(或其他動態語言)中的常量,私人成員,主格檢查等時,他都會失敗。人們什麼時候會學習? (單身人士課程可以重新定義一樣簡單) – delnan 2010-09-14 18:28:22

6

Python是一種非常開放的語言,不包含final關鍵字。 Python給你更多的自由去做事情,並假設你知道事情應該如何工作。因此,假設使用您的代碼的人將知道SOME_CONSTANT不應在代碼中的某個隨機點處分配一個值。

如果你真的想,你可以把這個常量放在一個getter函數中。

def getConstant() 
    return "SOME_VALUE" 
+5

做'getConstant = lambda:new_value'仍然是可能的(並且只是稍微複雜一些)。由於'ALL_CAPS'是應該是常量的約定,所以你應該堅持這一點。 – delnan 2010-09-14 18:25:02

相關問題