我可以阻止在Python中修改对象吗?

时间:2010-09-14 18:08:32

标签: python global-variables

我希望以在程序初始化代码中只设置一次的方式控制全局变量(或全局范围变量),并在此之后锁定它们。

我使用UPPER_CASE_VARIABLES作为全局变量,但我想确定无论如何都不要更改变量。

  • python是否提供(或类似)功能?
  • 如何控制全局范围变量?

3 个答案:

答案 0 :(得分:14)

Activestate有一个名为Constants in Python的食谱,由古老的Alex Martelli创建一个const模块,其中的属性在创建后无法反弹。这听起来像你正在寻找的除了upcasing - 但可以通过检查属性名称是否全部大写来添加。

当然,这可以通过确定的方式来规避,但这就是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 it to prevent its deletion -- see
#  https://stackoverflow.com/questions/5365562/why-is-the-value-of-name-changing-after-assignment-to-sys-modules-name)
import sys
_ref, sys.modules[__name__] = sys.modules[__name__], _const()

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

    try:
        const.Answer = 42  # Not OK to create 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 be allowed!")

    try:
        const.ANSWER = 42  # Should be OK, all uppercase.
    except Exception as exc:
        raise RuntimeError("Defining a valid const attribute should be allowed!")
    else:  # Test succeeded - no exception generated.
        print('const.ANSWER set to %d raised no exception' % const.ANSWER)

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

输出:

const name 'Answer' is not all uppercase
const.ANSWER set to 42 raised no exception
Can't change const.ANSWER

答案 1 :(得分:7)

Python是一种非常开放的语言,不包含final个关键字。 Python让您可以更自由地做事,并假设您知道事情应该如何运作。因此,假设使用您的代码的人知道不应在代码中的某个随机点为SOME_CONSTANT分配值。

如果你真的想要,可以将常量包含在getter函数中。

def getConstant()
  return "SOME_VALUE"

答案 2 :(得分: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__就足够了(特别是如果你抛出一个异常)来警告那些正在使用代码的人,只能读取State的目标。如果有人仍然觉得需要修改状态,那么他们遇到的任何未定义的行为都不是我的错。