可变常数是否安全?

时间:2015-02-20 23:42:26

标签: python constants mutability

是否有任何类型的“陷阱”与一个列表或任何其他可变对象的常量相关联?

  

目前我的上下文与将传递给调用的常量有关,但我一般都会问这个问题,因为我不认为该主题会对问题产生有意义的影响。

考虑这个示例代码:

#!/usr/bin/env python
# This file was not tested before posting.

import subprocess

LS_FLAGS = ['-l', '-a']

def main():
    subprocess.call(['ls'] + LS_FLAGS)

if __name__ == '__main__':
    main()

我问这个是因为我对mutable objects in function definitions所产生的问题一无所知。并且,即使我理解,也不应该有任何事情进行任务或突变到一个受尊重的常数;并且“常数”并不是真正的东西:我问,并且进一步问,是否可能存在一些语义上保护自我的惯例不是偶然的突变?

2 个答案:

答案 0 :(得分:2)

不必担心变异可以使代码更易于推理,因此,它是纯函数式编程的核心原则之一。

在这种特殊情况下,它似乎不是一个严重的问题,甚至可能被认为是一个特征。如果您觉得没有理由可以修改LS_FLAGS,则可以随时将其定义为元组,但如果您愿意,代码的用户可以完全重新声明LS_FLAGS

答案 1 :(得分:0)

您可以通过从类字典对象访问“常量”来防止变异。有点像''那样',或许:

class Config:
    _config = dict(
        LS_FLAGS=['-l', '-a']
    )
    def __getitem__(self, idx):
        return Config._config[idx].copy()  # Use copy.deepcopy 
                                           # instead if required

CONFIG=Config()

甚至:

class Config:
    def __getitem__(self, idx):
        if idx == 'LS_FLAGS':
            return ['-l', '-a']

        raise KeyError(idx)

CONFIG=Config()

然后使用CONFIG这样的对象:

print(CONFIG['LS_FLAGS'])

这远非完美(并且不是很性感),但这会阻止意外 1 废弃你的“常数”:

# Try to mutate the constant config
ls_flags = CONFIG['LS_FLAGS']
ls_flags.append('/home')

print(CONFIG['LS_FLAGS']) # unchanged

CONFIG['LS_FLAGS'] = ['-ls']

将举起TypeError: 'Config' object does not support item assignment


¹当然,由于Python没有“真正的”常量,因此无法保护您免受恶意代码的攻击。例如,可以完全替换CONFIG对象...