2010-09-14 53 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

相关问题