ThorSummoner
ThorSummoner

Reputation: 18189

Are mutable constants safe?

Are there any sort of 'gotchas' associated with having a constant that is a list, or any other mutable object?

Currently my context has to do with constants that will be passed to a call, but I ask the question generically as I don't feel that topic impacts the question meaningfully.

Consider this example code:

#!/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()

I ask this because I am deathly aware of the problems that an arise from mutable objects in function definitions; And, even as I understand that there should never be anything doing assignment or mutation to a respected constant; and that "constants" are not really a thing: I ask, and further ask, might there be some conventions for semantically protecting ones self again't accidental mutations?

Upvotes: 2

Views: 1228

Answers (2)

Sylvain Leroux
Sylvain Leroux

Reputation: 52060

You can prevent mutation by accessing your "constants" from a dictionary-like object. Something ''like'' that, maybe:

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()

Or even:

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

        raise KeyError(idx)

CONFIG=Config()

Then use the CONFIG object like that:

print(CONFIG['LS_FLAGS'])

This is far from perfect (and not very sexy), but this will prevent accidental1 trashing of your "constants":

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

print(CONFIG['LS_FLAGS']) # unchanged

And

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

Will raise TypeError: 'Config' object does not support item assignment


¹Of course, as Python does not have "real" constants, that will not protect you against malicious code. For example, one can completely replace the CONFIG object...

Upvotes: 0

kindall
kindall

Reputation: 184395

Not having to worry about mutation can make code easier to reason about, and as such, it's one of the core tenets of pure functional programming.

In this specific case, it doesn't seem like it would be a serious issue, and might even be argued to be a feature. You can always define LS_FLAGS as a tuple if you feel there is no reason for it to be modifiable, but the user of your code can always redeclare LS_FLAGS entirely if they like.

Upvotes: 2

Related Questions