Clarification regarding abseil library flags
Question:
There is a statement in the abseil documentation that is as follows:
When one Python module imports another, it gains access to the other’s flags. (This behavior is implemented by having all modules share a common, global registry object containing all the flag information.)
When one module imports another — gaining access to the other’s flags — is the reverse true? In other words, does the model being imported also have access to the importing model’s flags? In terms of behaviour, it seems like this is the case. Is the general rule supposed to be that any two python files with some sort of import connection have access to each other’s flags, and that this condition is transitive?
Here are three files that demonstrate the behaviour to which I am referring.
sample.py
from absl import app
from absl import flags
import sample2
FLAGS = flags.FLAGS
flags.DEFINE_string('name', 'Jane Random', 'Your name.')
def main(argv):
print(FLAGS.name, "is being called in sample.py.")
print(FLAGS.Flag2) #Flag2 is a flag of sample3.py.
sample2.Sample()
if __name__ == '__main__':
app.run(main)
sample2.py:
from absl import app
from absl import flags
import sample3
FLAGS = flags.FLAGS
flags.DEFINE_string('Flag1', 'Jane Random', 'Your name.')
class Sample:
def a_method(self):
print(FLAGS.name, "is being called in sample2.py.") #sample.py's flags appear to be accessible even though we're not importing from there.
def __init__(self):
self.a_method()
sample3.Sample()
sample3.py
from absl import app
from absl import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('Flag2', 'This is a sample3.py flag.')
class Sample:
def a_method(self):
print(FLAGS.name, "is being called in sample3.py.") #sample.py's flags appear to be accessible even though we're not importing from there.
def __init__(self):
self.a_method()
Answers:
When you’re settings FLAGS = flags.FLAGS
you’re importing flags._flagvalues.FLAGS
.
flags._flagvalues.FLAGS
is an instance of the FlagValues
class defined in _flagvalues
.
The reason they can all access the same flags is because they are referring to the same object so any file can refer to the same flags.
If you want to overwrite this you can create a new FlagValues
instance and add flags to it by passing it as an argument, e.g.
NEW_FLAGS = flags.FlagValues()
new_flag = flags.DEFINE_string('name', 'default', 'help', flag_values=NEW_FLAGS)
The default arguments to flag_values
is always _flag_values.FLAGS
does the model being imported also have access to the importing model’s flags? In terms of behaviour, it seems like this is the case.
I am not sure if this deduction is correct.
In my testing, it seems that:
- when you import
sample2.py
into sample.py
, sample.py
has access to the flags inside sample2.py
, but sample2.py
doesn’t have access to the flags defined in sample.py
:
-
FLAGS.Flag1
in the following example is defined in sample2.py
and can be accessed in sample.py
.
-
But FLAGS.name
defined in sample.py
cannot be accessed in sample2.py
If we simplify your example a bit, like:
sample.py
from absl import app
from absl import flags
import sample2
FLAGS = flags.FLAGS
flags.DEFINE_string('name', 'Jane Random', 'Your name.')
def main(argv):
print(FLAGS.name, "is being called in sample.py.")
print(FLAGS.Flag1) # Flag1 is a flag of sample2.py.
if __name__ == '__main__':
app.run(main)
sample2.py:
from absl import app
from absl import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('Flag1', 'Jane Random', 'Your name.')
print(FLAGS.name, "printing from sample2.py.")
When running the above:
(venv) jcnarasimhan@hadr-crdhost:~/PycharmProjects/hadr/absl_exploration$ python sample.py
Traceback (most recent call last):
File "/home/jcnarasimhan/PycharmProjects/hadr/absl_exploration/sample.py", line 3, in <module>
import sample2
File "/home/jcnarasimhan/PycharmProjects/hadr/absl_exploration/sample2.py", line 7, in <module>
print(FLAGS.name, "printing from sample2.py.")
File "/home/jcnarasimhan/PycharmProjects/hadr/venv/lib/python3.9/site-packages/absl/flags/_flagvalues.py", line 471, in __getattr__
raise AttributeError(name)
AttributeError: name
There is a statement in the abseil documentation that is as follows:
When one Python module imports another, it gains access to the other’s flags. (This behavior is implemented by having all modules share a common, global registry object containing all the flag information.)
When one module imports another — gaining access to the other’s flags — is the reverse true? In other words, does the model being imported also have access to the importing model’s flags? In terms of behaviour, it seems like this is the case. Is the general rule supposed to be that any two python files with some sort of import connection have access to each other’s flags, and that this condition is transitive?
Here are three files that demonstrate the behaviour to which I am referring.
sample.py
from absl import app
from absl import flags
import sample2
FLAGS = flags.FLAGS
flags.DEFINE_string('name', 'Jane Random', 'Your name.')
def main(argv):
print(FLAGS.name, "is being called in sample.py.")
print(FLAGS.Flag2) #Flag2 is a flag of sample3.py.
sample2.Sample()
if __name__ == '__main__':
app.run(main)
sample2.py:
from absl import app
from absl import flags
import sample3
FLAGS = flags.FLAGS
flags.DEFINE_string('Flag1', 'Jane Random', 'Your name.')
class Sample:
def a_method(self):
print(FLAGS.name, "is being called in sample2.py.") #sample.py's flags appear to be accessible even though we're not importing from there.
def __init__(self):
self.a_method()
sample3.Sample()
sample3.py
from absl import app
from absl import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('Flag2', 'This is a sample3.py flag.')
class Sample:
def a_method(self):
print(FLAGS.name, "is being called in sample3.py.") #sample.py's flags appear to be accessible even though we're not importing from there.
def __init__(self):
self.a_method()
When you’re settings FLAGS = flags.FLAGS
you’re importing flags._flagvalues.FLAGS
.
flags._flagvalues.FLAGS
is an instance of the FlagValues
class defined in _flagvalues
.
The reason they can all access the same flags is because they are referring to the same object so any file can refer to the same flags.
If you want to overwrite this you can create a new FlagValues
instance and add flags to it by passing it as an argument, e.g.
NEW_FLAGS = flags.FlagValues()
new_flag = flags.DEFINE_string('name', 'default', 'help', flag_values=NEW_FLAGS)
The default arguments to flag_values
is always _flag_values.FLAGS
does the model being imported also have access to the importing model’s flags? In terms of behaviour, it seems like this is the case.
I am not sure if this deduction is correct.
In my testing, it seems that:
- when you import
sample2.py
intosample.py
,sample.py
has access to the flags insidesample2.py
, butsample2.py
doesn’t have access to the flags defined insample.py
:-
FLAGS.Flag1
in the following example is defined insample2.py
and can be accessed insample.py
. -
But
FLAGS.name
defined insample.py
cannot be accessed insample2.py
-
If we simplify your example a bit, like:
sample.py
from absl import app
from absl import flags
import sample2
FLAGS = flags.FLAGS
flags.DEFINE_string('name', 'Jane Random', 'Your name.')
def main(argv):
print(FLAGS.name, "is being called in sample.py.")
print(FLAGS.Flag1) # Flag1 is a flag of sample2.py.
if __name__ == '__main__':
app.run(main)
sample2.py:
from absl import app
from absl import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('Flag1', 'Jane Random', 'Your name.')
print(FLAGS.name, "printing from sample2.py.")
When running the above:
(venv) jcnarasimhan@hadr-crdhost:~/PycharmProjects/hadr/absl_exploration$ python sample.py
Traceback (most recent call last):
File "/home/jcnarasimhan/PycharmProjects/hadr/absl_exploration/sample.py", line 3, in <module>
import sample2
File "/home/jcnarasimhan/PycharmProjects/hadr/absl_exploration/sample2.py", line 7, in <module>
print(FLAGS.name, "printing from sample2.py.")
File "/home/jcnarasimhan/PycharmProjects/hadr/venv/lib/python3.9/site-packages/absl/flags/_flagvalues.py", line 471, in __getattr__
raise AttributeError(name)
AttributeError: name