Reputation: 18189
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
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
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