Python Viewing Rules sys.argv

I just noticed that sys.argv is visible in the imported script.

A.py

import sys print("A") print(sys.argv) import B 

B.py

 import sys print("B") print(sys.argv) 

Productivity

 >> python A.py --foo bar >> A >> ['path/to/A.py', '--foo', 'bar'] >> B >> ['path/to/A.py', '--foo', 'bar'] 

This is good, since now I do not need to parse the argument in the main script (aka. Manage.py).

The question is: can I rely on this behavior? Are there any cases where this does not work?

+6
source share
4 answers

Module attributes, such as sys.argv , are objects. No matter which module you are accessing from, they are the same object.

It also means that if one module modifies sys.argv , then this change will also affect any other module that accesses sys.argv .


Coding Style Tip:

Although you can access sys.argv from two different modules, I would not recommend it, and here's why.

I like scripts that can also be double as modules. This gives you maximum flexibility when reusing code. sys.argv only makes sense when the code is called as a script. In order for the code to be useful as a module, the code should not depend on finding values ​​in sys.argv .

Therefore, I would recommend parsing sys.argv once in the main script call:

 if __name__ == '__main__': import argparse def parse_args(): ... # argparse uses sys.argv args = parse_args() 

and then passing the values ​​to args in the function as needed.

Thus, everything that is outside the if __name__ == 'main__' should not depend on sys.argv and therefore can be used through simple function calls or importing modules.

+5
source

This has nothing to do with the scope of sys.argv , in particular, that all modules are loaded into one global instance.

So, if A.py imports a module, and then modifies it, if B.py imports the same module, it just gets access to the imported A.py module.

For instance:

A.py

 import sys sys.foo = "foo!" import B 

B.py

 import sys print sys.foo 

Running A.py here will import B.py , which will have access to the modified sys module and the foo variable inside it. However, if you must run B.py directly, this code will raise an error that sys.foo does not exist.

This is a very bad behavior to rely on, as it makes very strong assumptions about which module imports, and makes it extremely fragile.

+3
source

sys.argv installed in Modules/main.c at startup (with the PySys_SetArgv function).

Now it is possible that another module also calls PySys_SetArgv or PySys_SetArgvEx , but none of the standard modules seem to do this (Python 2.7), and it will either 1) Be part of something very specific, or 2) Idiotic

The so-called "argv clobbering" is sometimes used to set the name of the process, although modern systems provide better ways to do this, but since C argv values ​​are copied at startup, this should not be a problem, even if it will be used.

So yes. You can reasonably rely on sys.argv in all modules, although there are ways to break it if you really want to.

+1
source

sys.argv is set when the parent script is run. No matter what you import, it will not change anywhere.

0
source

All Articles