【问题标题】:Are mutable constants safe?可变常量安全吗?
【发布时间】:2015-02-20 23:42:26
【问题描述】:

是否存在与列表常量或任何其他可变对象相关的“陷阱”?

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

考虑这个示例代码:

#!/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 引起的问题;而且,即使据我所知,也不应该有任何事情对受人尊敬的常数进行分配或突变;并且“常量”并不是真正的东西:我问,并进一步问,是否有一些约定可以在语义上保护自身而不是意外突变?

【问题讨论】:

  • 您可以通过使用元组而不是列表从等式中删除突变:LS_FLAGS = ('-l', '-a') 是不可变的。如果以后使用时必须将其作为列表,请使用list(LS_FLAGS) 将其强制为列表。请注意,虽然元组是不可变的,但该元组中的可变对象仍然是可变的。这对字符串没有实际意义,但如果你的元组中有列表,你可以改变列表。
  • 你可以把它变成一个元组(它们是不可变的)。或者您是否要求类似于 Java 的 final 关键字,因此您不能在实例化后为变量分配任何不同的值?
  • 我不认为 python 知道常量是什么......
  • 我最近在博客上写了关于如何创建一个不能更改属性的类作为常量容器的一种......以及它是如何实现的。 engyrus.com/2015/02/spt-3-constant-singleton.html

标签: python constants mutability


【解决方案1】:

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

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

【讨论】:

  • 我不知道我什至会有第一段(我给了你+1,因为你的是最正确的......)......但常量只是变量,这是带走的......它由编码人员意识到也许我不应该改变这个 ALL_CAPS_VARIABLE
【解决方案2】:

您可以通过从类似字典的对象中访问“常量”来防止突变。 ''喜欢''的东西,也许:

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对象...

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多