为什么Python不支持常量引用?

25 投票
5 回答
3295 浏览
提问于 2025-04-16 07:08

注意:我不是在讨论如何防止变量被重新绑定。我是在说如何防止修改变量所指向的内存,以及从那里通过嵌套容器可以访问的任何内存。

我有一个很大的数据结构,我想把它以只读的方式暴露给其他模块。在Python中,做到这一点的唯一方法就是深拷贝我想暴露的特定部分——在我的情况下,这样做的成本太高了。

我相信这是一个非常常见的问题,似乎常量引用会是完美的解决方案。但我一定是遗漏了什么。也许在Python中实现常量引用很困难。也许它们的作用并不是我想的那样。

任何见解都将不胜感激。


虽然这些回答很有帮助,但我没有看到任何理由说明在Python中实现const会很困难或不可行。我想“与Python风格不符”也可以算作一个有效的理由,但这真的成立吗?Python确实会对私有实例变量(以__开头)进行混淆,以避免意外的错误,而const在精神上似乎并没有太大不同。


编辑:我刚刚提供了一个非常小的悬赏。我想了解更多关于为什么Python没有const的细节。我怀疑原因是实现起来真的很难做到完美;我想知道为什么这么难。

5 个回答

8

关于任何编程语言,设计问题有很多,大部分的答案都是“就因为这样”。很明显,像这样的常量会与Python的理念相悖。


不过,你可以通过使用描述符来创建一个只读的类属性。这并不是特别简单,但也不算太难。它的工作原理是,你可以使用property装饰器来创建属性(看起来像属性但在访问时会调用一个方法);如果你只创建了一个获取器而没有设置器,那么你就会得到一个只读属性。使用元类编程的原因是,__init__接收到的是一个完全形成的类实例,所以在这个阶段你实际上无法将属性设置为你想要的值!相反,你必须在类创建时设置它们,这就需要用到元类。

以下是来自这个食谱的代码:

# simple read only attributes with meta-class programming

# method factory for an attribute get method
def getmethod(attrname):
    def _getmethod(self):
        return self.__readonly__[attrname]

    return _getmethod

class metaClass(type):
    def __new__(cls,classname,bases,classdict):
        readonly = classdict.get('__readonly__',{})
        for name,default in readonly.items():
            classdict[name] = property(getmethod(name))

        return type.__new__(cls,classname,bases,classdict)

class ROClass(object):
    __metaclass__ = metaClass
    __readonly__ = {'a':1,'b':'text'}


if __name__ == '__main__':
    def test1():
        t = ROClass()
        print t.a
        print t.b

    def test2():
        t = ROClass()
        t.a = 2

    test1()
13

这就像私有方法一样:作为成年人,代码的作者们应该自愿达成一致,定义一个接口,而不是靠强制。因为实际上,真正去严格执行这个约定是非常困难的,而半心半意的做法只会导致很多乱七八糟的代码。

使用只读的描述符,并在你的文档中明确说明这些数据是只供读取的。毕竟,一个有决心的程序员可能会找到你没想到的其他使用你代码的方法。

10

PEP 351中,Barry Warsaw 提出了一个协议,用来“冻结”任何可变的数据结构,这就像 frozenset 让一个集合变得不可变一样。被冻结的数据结构可以被哈希,这样就可以用作字典中的键。

这个提议在python-dev上进行了讨论,其中Raymond Hettinger的批评是最详细的。

这可能不是你想要的答案,但这是我能找到的最接近的内容,应该能让你了解Python开发者在这个问题上的一些想法。

撰写回答