Trying to see the value of PYTHONHASHSEED
by using:
# (this is inside module_1.py)
os.environ['PYTHONHASHSEED']
raises a KeyError:
Traceback (most recent call last):
File "/home/black/Dev/Projects/module_1.py", line 2, in <module>
os.environ['PYTHONHASHSEED']
File "/usr/lib/python3.4/os.py", line 631, in __getitem__
raise KeyError(key) from None
KeyError: 'PYTHONHASHSEED'
Printing the contents of os.environ
by
for i in sorted(os.environ):
print(i)
# prints:
# CLUTTER_IM_MODULE
# COMPIZ_BIN_PATH
# ...
# etc.
reveals that PYTHONHASHSEED
is not inside, but I am pretty sure it should have a value since on Python 3.3 and greater, hash randomization is turned on by default.
Question:
Why can't I access its value this way and how can I access it through module_1.py
?
You can set PYTHONHASHSEED in a Python script, but it has no effect on the behavior of the hash()
function - it needs to be set in the environment of the interpreter before the interpreter starts up.
How to set its value using pure Python
The trick is to pass the environment variable to the Python interpreter in a subprocess.
import random
from subprocess import call
random.seed(37)
cmd = ['python', '-c', 'print(hash("abc"))']
for i in range(5):
hashseed = bytes(random.randint(0, 4294967295))
print('\nhashseed', hashseed)
call(cmd, env={'PYTHONHASHSEED': hashseed})
output
hashseed 2929187283
-972692480
hashseed 393430205
2066796829
hashseed 2653501013
1620854360
hashseed 3616018455
-599248233
hashseed 3584366196
-2103216293
You can change the cmd
list so that it runs the hashtest.py
script above:
cmd = ['python', 'hashtest.py']
or if hashtest.py
is executable,
cmd = './hashtest.py'
By passing a dict
as the env
argument we replace the default environment that would be passed to the command. If you need access to those other environment variables, then instead you should modify os.environ
in the calling script, with eg, os.environ['PYTHONHASHSEED'] = hashseed
.
How to set its value using Bash
First, we have a short Bash script pyhashtest.bsh
that uses the RANDOM environment variable as the seed for PYTHONHASHSEED. This variable must be exported so that the Python interpreter can see it. Then we run our Python script hashtest.py
. We do this in a loop 5 times so we can see that using different seeds has an effect on the hash value.
The Python script hashtest.py
reads PYTHONHASHSEED from the environment and prints it to show that it has the value we expect it to have. We then calculate & print the hash of a short string.
pyhashtest.bsh
#!/usr/bin/env bash
for((i=0; i<5; i++)); do
n=$RANDOM
echo "$i: Seed is $n"
export PYTHONHASHSEED="$n"
python hashtest.py
echo
done
hashtest.py
#!/usr/bin/env python
import os
s = 'abc'
print('Hashseed is', os.environ['PYTHONHASHSEED'])
print('hash of s is', hash(s))
typical output
0: Seed is 9352
Hashseed is 9352
hash of s is 401719638
1: Seed is 24945
Hashseed is 24945
hash of s is -1250185385
2: Seed is 17661
Hashseed is 17661
hash of s is -571990551
3: Seed is 24313
Hashseed is 24313
hash of s is 99658978
4: Seed is 21142
Hashseed is 21142
hash of s is -662114263
To run these programs, save them both into the same directory, eg the usual directory you run Python scripts from. Then open a Bash shell and navigate to that directory using the cd
command.
Eg, if you've saved the scripts to /mnt/sda2/fred/python
then you'd do
cd /mnt/sda2/fred/python
Next, make pyhashtest.bsh
executable using this command:
chmod a+x pyhashtest.bsh
Then run it with
./pyhashtest.bsh
"hash randomization is turned on by default" means (among other things) that it is turned on even if there is no PYTHONHASHSEED
environment variable - if the hash seed is not specified in the environment, one is chosen at random. This choice is done internally within python, and the os.environ
array is not updated.