It is not recommended to write if name__ == ‘__main’
Man, I hate to see bad advice, and that is really bad advice … there is a reason why the name guard has been a standard idiom of Python for years, and no one should be throwing about recommendations to break that. The name guard exists specifically to keep side effects from happening when the file is imported, which includes when you use the help builtin. Which you should do, a lot.
I’d argue it’s not bad advice depending on the reasoning why. I can assume that, if you’re using this idiom, you’re doing it to control whether a “main” function executes and that you’re probably also using the same file as an executable.
Setuptools’ entry_points option should be used instead. Doing this removes the need for the above idiom.
A blanket recommendation not to use any standard and long established language idiom is inherently bad advice, and in Python the name guard remains the idiomatic way to isolate code that is only meant to run if the individual module is executed, rather than imported.
A command line entry point (as with setuptools) or a main function is just one such use. So is a self test or demonstration code for a single module library, or for a single module within a larger package. If you’re using unittest then the unittest.main() call at the bottom of the file should always be inside a name guard.
Even saying that setuptools’ entry_points “should” be used instead is, arguably, bad advice… that’s only true if you’re packaging with setuptools. Sure, that’s the de facto (but still optional) toolchain for packaging, but that could change, and then you’d be left with a bunch of code that has hewn to the idiom of a dependency rather than to the idioms of the language itself. So does it remove the functional need for the name guard? Sure, for your programs publicly facing entry points… but dropping the idiom doesn’t make your code any better.
The article seems to suggest that Python doesn’t need an entry point function because it’s interpreted, but from what I recall of Scala it didn’t necessarily need one either. It seems instead related to how you think programs should be structured when you design the language – whether there is a global scope for declarations with special rules or not.
This was important to me when I wrote perl - I’d start a script with:
exit !main(@ARGV);
sub main { ... }
It helped me a lot with reading and understanding code. Perl and python will execute any top-level statements encountered - outside of function bodies. Which means “anything could happen” and you’d need to read down to see what was invoked where. It’s basically a forest of execution contexts (rooted at each top level statement), rather than a tree.
Doing the above made it back into a tree which you could navigate without having to scrutinise every line of the script.
Sadly, you can’t do this in python because python doesn’t parse-then-execute like perl, so you have to execute the whole file (in order to define your functions) and so also all the bits in-between your functions. You can’t get the benefit of knowing from the first few lines of the script that only functions are invoked.
Excuse me, but python is compiled to VM byte code like Java. Therefore it is a serious programming language, unlike those silly scripting languages like C++.
For a package, the same effect can be achieved by including a main.py module, the contents of which will be executed when the module is run with -m.
I really don’t agree with the author. The convention they describe and dismiss is a convention used so widely that I except many Python programmers look for it when going over a code base.
However, because Python has entry points the code that is invoked when you start a python program can be anything.
So to find where a Python program starts you have to look at setup.py and then you might also have to note what individual scripts a user might invoke.
Yeah. In this case I don’t care if it’s /technically/ correct - it’s the only way I’ve ever seen this done in one-file python scripts and I’ve never seen it in any bigger project, EXCEPT in the main .py file that was used as the entry point (if it was run via CLI and not via *WSGI), which makes it the de-facto way of running it if everyone uses it.
The theoretical nitpicking that this is not an automatically executed main() function should be clear to everyone but a beginner, but the if __name__ statement provides the same auto-magic entry point for people who want it that way.
And yes, I am 100% pro using this, just for the “I wrote this CLI script in python, but I have no global code in there, only classes and functions, and if I ever need it as a library, I can simply import from it.”
At first I was also disagreeing. But when thinking about it, almost all files where I had the if __name__ == '__main__': eventually happened to be refactored into several modules: the main module, deprived of this line (since it is always executed) and auxiliary modules exposing the reusable parts, mainly the parts used by the main module.
This is a response to that article, basically taking an position entirely counter to it, not a repost of the original. I’m not sure if this is suitable for folding?
It is, it keeps the discussion together, and (though this isn’t one) it disincentivizes hot takes by not rewarding them with their own slot on the front page.
I appreciate the motivation, but I still find it disappointing and unfair that newer (and frankly, higher-quality) content is merged away from the front page where few will see it.
I’m not sure that this is technically how folding works, but it appears that if multiple links are posted to similar topics within a time-span of roughly a few days, then they all share the “popularity factor” of whichever was posted first.
I feel like, if an article spurs multiple other people to write about the same topic (as happened in this case), then people are still talking about this topic, and so deserves at least one spot on the front page.
Maybe the comment threads could all be merged, but individual links preserved? Or all links on the topic could share the highest “popularity factor” instead?
Ok, the counterpoint is better, but there’s still a fundamental flaw in the language used in both cases.
No Python module is ever directly executed, at least not in the compiled language sense. The interpreter is executed, and then depending on invocation it either reads and interprets the contents of stdin in an interactive loop or it reads and interprets the contents of some file exactly as if it had received each line in an interactive loop.
A Python module is always interpreted; in an import xyz call it’s interpreted and directly added to the root global namespace, in a from xyz import * it’s interpreted and certain names within it are promoted to the root globals, in python xyz.py it’s interpreted as if cat’d to stdin, and in python -m xyz a search algorithm is employed to find the first of a series of files to then interpret as if cat’d to stdin.
In the last two cases the __name__ global is set to __main__ by convention, and it’s that convention that allows you to use a name guard to selectively enable (or less frequently disable) runtime functionality depending on if your module is being interpreted and imported or only interpreted.
The notion of a fixed main entry point is, in that model, somewhat absurd… why should the programmer be forced to name their entry point with that name? What if, for whatever reason, their module must import the name “main” from some other file, why not enable them to use whatever name makes the most sense for them?
Of course it’s a useful convention, and that’s why the name guard idiom exists, and certainly barring such a problem it’s best to name the primary entry point main just to make it easier for people to find and recognize… but because a Python module is very explicitly and intentionally NOT an executable file on any OS there’s no argument but tradition for making such a convention an actual reserved word in the language.
Man, I hate to see bad advice, and that is really bad advice … there is a reason why the name guard has been a standard idiom of Python for years, and no one should be throwing about recommendations to break that. The name guard exists specifically to keep side effects from happening when the file is imported, which includes when you use the
help
builtin. Which you should do, a lot.I’d argue it’s not bad advice depending on the reasoning why. I can assume that, if you’re using this idiom, you’re doing it to control whether a “main” function executes and that you’re probably also using the same file as an executable.
Setuptools’ entry_points option should be used instead. Doing this removes the need for the above idiom.
A blanket recommendation not to use any standard and long established language idiom is inherently bad advice, and in Python the name guard remains the idiomatic way to isolate code that is only meant to run if the individual module is executed, rather than imported.
A command line entry point (as with setuptools) or a
main
function is just one such use. So is a self test or demonstration code for a single module library, or for a single module within a larger package. If you’re using unittest then theunittest.main()
call at the bottom of the file should always be inside a name guard.Even saying that setuptools’ entry_points “should” be used instead is, arguably, bad advice… that’s only true if you’re packaging with setuptools. Sure, that’s the de facto (but still optional) toolchain for packaging, but that could change, and then you’d be left with a bunch of code that has hewn to the idiom of a dependency rather than to the idioms of the language itself. So does it remove the functional need for the name guard? Sure, for your programs publicly facing entry points… but dropping the idiom doesn’t make your code any better.
The article seems to suggest that Python doesn’t need an entry point function because it’s interpreted, but from what I recall of Scala it didn’t necessarily need one either. It seems instead related to how you think programs should be structured when you design the language – whether there is a global scope for declarations with special rules or not.
This was important to me when I wrote perl - I’d start a script with:
It helped me a lot with reading and understanding code. Perl and python will execute any top-level statements encountered - outside of function bodies. Which means “anything could happen” and you’d need to read down to see what was invoked where. It’s basically a forest of execution contexts (rooted at each top level statement), rather than a tree.
Doing the above made it back into a tree which you could navigate without having to scrutinise every line of the script.
Sadly, you can’t do this in python because python doesn’t parse-then-execute like perl, so you have to execute the whole file (in order to define your functions) and so also all the bits in-between your functions. You can’t get the benefit of knowing from the first few lines of the script that only functions are invoked.
So that’s what a scripting language is, eh? One that has an interpreter?
Behold, the C++ scripting language:
https://root.cern/cling/
Excuse me, but python is compiled to VM byte code like Java. Therefore it is a serious programming language, unlike those silly scripting languages like C++.
https://docs.python.org/3/library/__main__.html#module-__main__
I really don’t agree with the author. The convention they describe and dismiss is a convention used so widely that I except many Python programmers look for it when going over a code base.
However, because Python has entry points the code that is invoked when you start a python program can be anything.
So to find where a Python program starts you have to look at
setup.py
and then you might also have to note what individual scripts a user might invoke.Yeah. In this case I don’t care if it’s /technically/ correct - it’s the only way I’ve ever seen this done in one-file python scripts and I’ve never seen it in any bigger project, EXCEPT in the main
.py
file that was used as the entry point (if it was run via CLI and not via *WSGI), which makes it the de-facto way of running it if everyone uses it.The theoretical nitpicking that this is not an automatically executed
main()
function should be clear to everyone but a beginner, but theif __name__
statement provides the same auto-magic entry point for people who want it that way.And yes, I am 100% pro using this, just for the “I wrote this CLI script in python, but I have no global code in there, only classes and functions, and if I ever need it as a library, I can simply import from it.”
At first I was also disagreeing. But when thinking about it, almost all files where I had the
if __name__ == '__main__':
eventually happened to be refactored into several modules: the main module, deprived of this line (since it is always executed) and auxiliary modules exposing the reusable parts, mainly the parts used by the main module.Mods (@alynpost @pushcx) please fold into https://lobste.rs/s/fumh1r/why_doesn_t_python_have_main_function (fumh1r).
This is a response to that article, basically taking an position entirely counter to it, not a repost of the original. I’m not sure if this is suitable for folding?
It is, it keeps the discussion together, and (though this isn’t one) it disincentivizes hot takes by not rewarding them with their own slot on the front page.
Unfortunately the OP didn’t do so well so I didn’t even know this link was submitted. Thanks for folding!
I appreciate the motivation, but I still find it disappointing and unfair that newer (and frankly, higher-quality) content is merged away from the front page where few will see it.
I’m not sure that this is technically how folding works, but it appears that if multiple links are posted to similar topics within a time-span of roughly a few days, then they all share the “popularity factor” of whichever was posted first.
I feel like, if an article spurs multiple other people to write about the same topic (as happened in this case), then people are still talking about this topic, and so deserves at least one spot on the front page.
Maybe the comment threads could all be merged, but individual links preserved? Or all links on the topic could share the highest “popularity factor” instead?
Stories are ranked by “hotness”, calculated here.
I see, thanks for the clarification!
Having a counterpoint in the same context is valuable.
Ok, the counterpoint is better, but there’s still a fundamental flaw in the language used in both cases.
No Python module is ever directly executed, at least not in the compiled language sense. The interpreter is executed, and then depending on invocation it either reads and interprets the contents of stdin in an interactive loop or it reads and interprets the contents of some file exactly as if it had received each line in an interactive loop.
A Python module is always interpreted; in an
import xyz
call it’s interpreted and directly added to the root global namespace, in afrom xyz import *
it’s interpreted and certain names within it are promoted to the root globals, inpython xyz.py
it’s interpreted as if cat’d to stdin, and inpython -m xyz
a search algorithm is employed to find the first of a series of files to then interpret as if cat’d to stdin.In the last two cases the
__name__
global is set to__main__
by convention, and it’s that convention that allows you to use a name guard to selectively enable (or less frequently disable) runtime functionality depending on if your module is being interpreted and imported or only interpreted.The notion of a fixed
main
entry point is, in that model, somewhat absurd… why should the programmer be forced to name their entry point with that name? What if, for whatever reason, their module must import the name “main” from some other file, why not enable them to use whatever name makes the most sense for them?Of course it’s a useful convention, and that’s why the name guard idiom exists, and certainly barring such a problem it’s best to name the primary entry point
main
just to make it easier for people to find and recognize… but because a Python module is very explicitly and intentionally NOT an executable file on any OS there’s no argument but tradition for making such a convention an actual reserved word in the language.