Search code examples
pythonabseil

Clarification regarding abseil library flags


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

Solution

  • 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