Why do we need "__main__" guard in python code?
We all have seen code where we have protected the python code with "__main__" guard. Why do we need this? take a look at below explanationFile - grepinfiles.py
importsysdefgrep(ptrn,txtfl):withopen(txtfl)asf:forlineinf:ifptrninline:yieldline.rstrip('\n')ptrn,txtfl=sys.argv[1],sys.argv[2]formatchlineingrep(ptrn,txtfl):print(matchline)
For a sample input file
>>cat /tmp/1.txt This is a sample code for grep we do no have any example for egrep
We get the below output
pythongrepinfiles.pyegrep/tmp/1.txtwedonohaveanyexampleforegrep
Now, lets use this module as package in another module.
File: finderror.py
importsysfromgrepinfilesimportfindpatterntxtfl=sys.argv[1]forlineinfindpattern('ERROR',txtfl):print(line)
when you run this function, we get the below output.
>>pythonfinderror.py/tmp/1.txtTraceback(mostrecentcalllast):File"finderror.py",line2,in<module>fromgrepinfilesimportfindpatternFile"/home/user/workspace/blog_examples/python_name_gaurd/grepinfiles.py",line9,in<module>ptrn,txtfl=sys.argv[1],sys.argv[2]IndexError:listindexoutofrange
Why is this error???
Magic variable called "__name__"
Now, lets modify the code slightly and run the same command.
File: grepinfiles.py
importsysdeffindpattern(ptrn,txtfl):print("Inside the module",__name__)withopen(txtfl)asf:forlineinf:ifptrninline:yieldline.rstrip('\n')if__name__=="__main__":ptrn,txtfl=sys.argv[1],sys.argv[2]formatchlineinfindpattern(ptrn,txtfl):print(matchline)
and
File: finderror.py
importsysfromgrepinfilesimportfindpatternif__name__=="__main__":txtfl=sys.argv[1]forlineinfindpattern('ERROR',txtfl):print(line)
Now, check the output for the modified source code
>>pythongrepinfiles.pyegrep/tmp/1.txt('Insidethemodule','__main__')wedonohaveanyexampleforegrep>>pythonfinderror.py/tmp/1.txt('Insidethemodule','grepinfiles')
Explanation
The main package which is invoked by the python interpreter will have __name__ variable set to __main__
Any other module/package which is invoked by main package/module will have __name__ as the module name itself.
So, when finderror.py was invoked,
- finderror.py module will have __name__ set to __main__
- grepinfiles.py module will have __name__ set to 'grepinfiles'
However, when only grepinfiles.py was invoked,
- grepinfiles.py module will have __name__ set to '__main__'
Conclusion
Name guard is a mechanism to customize your python module/package to run any specific code for the module when invoked independently. Also, it is a mechanism to safeguard the code base which are not to be executed when invoked from other up-stream modules/functions.