no additional indentation with if __name__ == "__main__": - python

i know that it is good style to define a main() method for "script-style" python programs so it can optionally be included as a module later on.
so let's assume this code (random snippet):
a = 5
if a > 0:
print a
becomes
def main():
a = 5
if a > 0:
print a
if __name__ == "__main__":
main()
causing all my code to be indented one more level.
i try to avoid unnecessary indentation/nesting in my code for maximum clarity, and thus i am wondering if something can be done here, like e.g.
if __name__ != "__main__":
return # just leave this file
a = 5
if a > 0:
print a
but (of course) this triggers:
SyntaxError: 'return' outside function
is something like this possible? advisable? idiomatic?

You can do this:
if __name__ != "__main__":
throw TypeError("Attempted to import command-line only script")
# Your code here
However, I would advise against this pattern - most of the time it should be pretty obvious that a script is command-line only. And if someone has a use case for something that you defined in a script they shouldn't have to edit it just to be able to import one function.

Nope, not possible, really.
When __name__ is not '__main__' your module was imported by another piece of code, as a regular module. You cannot bail out early in that case.
And what's wrong with a one time extra indentation level? Just hit tab in the editor, and be done with it? Personally, I find that using a main() function documents the intent much better than leaving the code unindented.

A function should do one thing and this also applies to main. It should do (some) main stuff and everything else should be done in functions and classes.
There is absolutely no reason to see this as an "unnecessary indentation"…

You'd have to induce the importer itself to behave differently. It might be possible, though difficult, but certainly not advisable, as you'd be introducing some very unexpected behavior.
If you really want to avoid the extra indentation, you could, I suppose, implement a 'public' and 'private' module, where the public module branches based on if __name__ == '__main__' to load a different private module. But that seems like a lot of hoops to jump through to avoid a few extra indentations. In any case, if your main() is long enough that the indentation is bugging you, you should probably think about breaking more of it out in to functions in the first place.

Related

Gradescope failed to execute [duplicate]

I have this code:
import sys
def random(size=16):
return open(r"C:\Users\ravishankarv\Documents\Python\key.txt").read(size)
def main():
key = random(13)
print(key)
When I try running the script, there are no errors, but nothing appears to happen. I expected it to print some content from the key file, but nothing is printed.
What is wrong? How do I make the code run?
You've not called your main function at all, so the Python interpreter won't call it for you.
Add this as the last line to just have it called at all times:
main()
Or, if you use the commonly seen:
if __name__ == "__main__":
main()
It will make sure your main method is called only if that module is executed as the starting code by the Python interpreter. More about that here: What does if __name__ == "__main__": do?
If you want to know how to write the best possible 'main' function, Guido van Rossum (the creator of Python) wrote about it here.
Python isn't like other languages where it automatically calls the main() function. All you have done is defined your function.
You have to manually call your main function:
main()
Also, you may commonly see this in some code:
if __name__ == '__main__':
main()
There's no such main method in python, what you have to do is:
if __name__ == '__main__':
main()
Something does happen, it just isn't noticeable
Python runs scripts from top to bottom. def is a statement, and it executes when it is encountered, just like any other statement. However, the effect of this is to create the function (and assign it a name), not to call it. Similarly, import is a statement that loads the other module (and makes its code run top to bottom, with its own global-variable context), and assigns it a name.
When the example code runs, therefore, three things happen:
The code for the sys standard library module runs, and then the name sys in our own module's global variables is bound to that module
A function is created from the code for random, and then the name random is bound to that function
A function is created from the code for main, and then the name main is bound to that function
There is nothing to call the functions, so they aren't called. Since they aren't called, the code inside them isn't run - it's only used to create the functions. Since that code doesn't run, the file isn't read and nothing is printed.
There are no "special" function names
Unlike in some other languages, Python does not care that a function is named main, or anything else. It will not be run automatically.
As the Zen of Python says, "Explicit is better than implicit". If we want a function to be called, we have to call it. The only things that run automatically are the things at top level, because those are the instructions we explicitly gave.
The script starts at the top
In many real-world scripts, you may see a line that says if __name__ == '__main__':. This is not "where the script starts". The script runs top to bottom.
Please read What does if __name__ == "__main__": do? to understand the purpose of such an if statement (short version: it makes sure that part of your top-level code is skipped if someone else imports this file as a module). It is not mandatory, and it does not have any kind of special "signalling" purpose to say where the code starts running. It is just a perfectly normal if statement, that is checking a slightly unusual condition. Nothing requires you to use it in a script (aside from wanting to check what it checks), and nothing prevents you from using it more than once. Nothing prevents you from checking whether __name__ is equal to other values, either (it's just... almost certainly useless).
You're not calling the function. Put main() at the bottom of your code.

putting inner python function at the bottom of the code

How can I put an inner python function at the bottom of the code, and call it from the beginning?
For example, VBA dosent care where the phisical inner function code is.
Rexx ( which is also interpreter) also does not care.
How can I do it in Python?
It is much easier to understand the code when the functions are at the bottom.
thanks
You could not do that.
Python runs your code from top to bottom, so it first needs to declare your functions to access them later. You can not first access, later declare, because you would tring to access non exsistent values.
In compiled code, it may works. But in script languages, like python, it does not. As far as I know.
You can do like this:
def main():
print(f(3))
def f(x):
return x * x
if __name__ == "__main__":
main()
Or do you talk about nested functions?
BTW: using the construct in the bottom of my example is anyway good practice to execute the main code only if the module is called as a script. And if it isn't, code shouldn't be extensively executed anyhow before the module is imported (and functions called from outside).

Why def main(argv=[__name__]) and if __name__ == "__main__": sys.exit(main(sys.argv))?

I'm working with/rewriting a code that first defines a function as follows:
def main(argv=[__name__]):
...
*rest of code*
...
and ends with:
if __name__ == "__main__":
sys.exit(main(sys.argv))
I'm under the impression that what this is doing is checking to make sure that the script is being executed from the command line, and then running the function main with the arguments provided as it exits python. But then, why is it necessary to preset the variable argv to [__name__] in the function definition? This is not my code, so I don't know the original intention behind this. I am, however, new to using if __name__ == "__main__": lines to spot check command line execution, so maybe there is some glaringly obvious reason for this syntax that I'm missing. Any help, or further detail on main function definition and argument/command-line-vs-module testing would be appreciated.
As for the argv=[__name__], the original dev probably wanted to keep the option to run this function not from the command line (i.e. invoked by another module), and provided __name__ because it uses sys.argv[0] for some functionality.
The main function is nothing to do with python, just some convention (derived from languages like C). sys.exit(main(sys.argv)) will trigger the sys.exit function with an exit code equivalent to the product of running the main function with the received command line arguments. main probably should return an appropriate exit code (0 is to indicate OK, others imply various exceptions).
The main() definition allows for the possibility that main() will be called in other ways than the sys.exit() line at the bottom of the file. This might be an example of defensive programming, or it might indicate other supported uses of this file.
One such other supported use might be to invoke it from another Python program, like so:
import your_module
your_module.main()
When a script is run from the CLI, argv[0] is the name of the script, and the rest of argv is the command-line arguments. So the rest of main() may expect that argv[0] will always be filled in.
The default value is ensuring that argv[0] has something analogous in it when the file is being imported instead of being run directly. In this case, it's the name of the module.

Designing a program entry point in python

The main file, that intended to run everything, is now a mess of a dozen of variables (which are global by default in the top-level control flow), couple of structures and a middle-sized main loop. From other languages I've learned that globals are evil. I tend to put it all into a class in the same file and call just one method from a global control flow like following:
def MyClass:
def __init__(self):
self.value1 = 1
....
if __name__ == "__main__":
#inspect sys.argv here
MyClass().main_proc()
Would you consider it a design plus? Is there a pythonic way to do this?
Python does not force you to use OOP like e.g. Java or C#, so you don't need to put stuff into classes if there is no real benefit from that for you.
Especially creating a class instance just to group stuff is not the best way to go IMHO. You could extract that stuff into a module instead. This does not require any instances, it just needs to be imported. That way it's also in a separated file and namespace.
Example:
main.py:
if __name__ == "__main__":
import sys
args = sys.argv[1:]
if len(args) != 2:
print("This script requires exactly two command-line arguments!")
exit(1)
import my_module
exit_code = my_module.run(args) or 0
exit(exit_code)
else:
raise ImportError("Run this file directly, don't import it!")
my_module.py:
# initialization code to be run at import time goes here
def run(args):
# do whatever you need to do
print("Hello world!")
print("You said <", args[0], "> and <", args[1], ">."
# you may return an integer (1-255) as exit code if an error occurred,
# else the default exit code is 0 (successful; no error)
However, don't take this approach as ultimate truth! It's my personal, (not so) humble opinion, but there are always some situations where one approach fits better, and some where others should be preferred.
Also this is mainly a design question and has no real impact on the stability or functionality of your programs. It may only improve the readability, but especially for small scripts it's not a good approach as it adds a lot of code that doesn't really do anything. It's only useful if you have a large project with several modules, I'd say.
For rather small scripts (single file or only very few modules) I would recommend to just define all classes and functions you need at the top and then use the standard if __name__ == "__main__" as entry point.

Design: Code after "if __name__ == __main__" test

I want to hear an opinion on the question: Is it a bad idea to have a lot of code after
if __name__ == '__main__':
The reason I'm asking this is, My current project has about 400 hundred lines of code, and as it grows, I keep adding lines after above statement. So this program is expected to be about 3000 lines of code and I'm worry , that I will have too much code after this statement. So the question 'Is it a good pythonic way to write a lot of code after this statement?'
A simple alternative is to just add your main code into a main() function, and simply call it after the __name__ check. That way, you get:
the benefits of the __name__ check
the benefits of a function (which may or may not be reusable)
the benefit of introspection (e.g. if you ever needed it, it would be easy to automatically analyze what the "main" code of a module is - it's just the main function!).
An example:
def main():
# Be awesome here.
if __name__ == '__main__':
main() # or sys.exit(main()), if you want to return an exit code
It sounds like there are two distinct points to make here:
All other things being equal, it is better for readability, testability, maintainability (and perhaps some other values of "-ability") to define functions that encapsulate the behavior that is represented by 400 lines of imperative code.
Code qualified by __name__ == '__main__' is only executed when the file is called directly, as opposed to being included as a module with import. So, a file like
def be_awesome():
pass
if __name__ == '__main__':
def be_more_awesome():
pass
will only have a definition for be_more_awesome when provided as the source argument to an invocation of python, not when being imported. As a general rule, then, it's appropriate to put after the __name__ test precisely the code that should be run only when the file is run as a script directly. Ask yourself these questions
"Would it be bad for this code to run if I imported this module in another file?"
"Does this code need to be called when I call this file directly?" (as in the case of a hypothetical main function that encapsulates your 400 lines)
If the answer to either of these questions is "yes", it (probably) belongs after the __name__ test; if not, it (probably) does not.
If you want to reuse your code, you shouldn't keep it after if __name__ == '__main__' (use this for functions/classes/modules and make the simplest call possible from this part of the program). And let me mention here the Zen of Python (two points at least matter in your case):
Sparse is better than dense.
Readability counts.

Categories

Resources