Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

70%
+5 −1
Q&A How and where does Python code start running? How can I control that?

Starting up Python There are several key ways to use the python command from the command line: python by itself starts a REPL that allows typing in and running Python code on the fly, one sta...

posted 8mo ago by Karl Knechtel‭  ·  edited 6mo ago by Karl Knechtel‭

Answer
#3: Post edited by user avatar Karl Knechtel‭ · 2024-06-15T08:50:40Z (6 months ago)
move content about `if __name__ == '__main__':` to a new Q&A
  • ## Starting up Python
  • There are several key ways to use the `python` command from the command line:
  • * `python` by itself starts a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) that allows typing in and running Python code on the fly, one statement at a time.
  • * `python myscript.py` runs the code in `myscript.py`, assuming it's in the current directory. Python will not search for the file to run; the path needs to be given explicitly on the command line.
  • * `python -c "code here"` treats the text supplied as a `-c` argument as Python code and runs it directly. (This example will report a `SyntaxError`, because `code here` is not valid Python code.)
  • * `python -m myscript` tries to find a *module named* `myscript` and run it.
  • Finally, when using one of the latter three methods, it's also possible to pass the `-i` ("interactive") flag. This makes Python start up a REPL *after* running the other specified code, and any global variables from that code will be available in the interpreter.
  • ### Understanding the `-m` flag
  • <details><summary>
  • Using `python -m` to run the code differs from giving a file name or path in several ways:
  • </summary>
  • * The supplied name needs to be a *module* path, the way it would look in an absolute `import` statement inside the code. Since we would import `myscript.py` (assuming everything else were set up properly) using something like `import myscript` (with no `.py`), that's how the command looks: `python -m myscript` (with no `.py`).
  • * This changes the rules for where Python looks for modules. If for example we had `myscript.py` inside of `myfolder`, then `python -m myfolder.myscript` tell Python that *the current directory (`.`) is a place that may contain modules and packages. But `python myfolder/myscript.py` will tell Python that *the `myfolder` directory* is a place that may contain modules and packages.
  • * Python will *search for* the named module, instead of following a specific file path. This is important because some standard library modules (and possibly some third-party packages) offer their own command-line interface, and can be run like scripts instead of just importing them from one's own code.
  • * Starting the code this way will also import packages for folders along the way: `python -m myfolder.myscript` will make `myfolder` a package (and run code in `myfolder/__init__.py`, if there is such a file). This also allows relative imports to work.
  • </details>
  • ## Where code starts running
  • <details><summary>Background understanding</summary>
  • It's important to understand that from Python's perspective, running a script is not much different from importing a module. Either way, the code is run *from top to bottom* in the file. **Any code that isn't indented happens immediately, in order.** (Some code that *is* indented might still happen: for example, code inside an `if` block would run if the condition is satisfied.) This includes things like `import` statements, by the way: they aren't required to be at the top of the file (although this is *usually a good idea*), and they happen when Python encounters them, not automatically.
  • Keep in mind that this does *not* mean that functions are called: "running" the code in the question simply *creates* the function - it doesn't make the code inside the function run.
  • There are **no "special" function names** here. Python won't automatically call a function named `main`, or anything else - functions only run when they are called.
  • </details>
  • ### Strategies for calling `my_function`
  • Therefore, in order for `my_function` to run in the example code, there has to be a call like `my_function()` somewhere. There are a few ways to make this happen:
  • * Start the interpreter like `python`; then use the REPL to `import myscript` and call `myscript.my_function()`. (Or similar ideas, like using `from myscript import my_function` and then `my_function()`.)
  • * Use `python -c` to specify similar code: `python -c "import myscript; myscript.my_function()"`.
  • * Add code like `my_function()` "at top level", so that it runs immediately, and calls the function. Keep in mind that *the function has to appear first in the file* - otherwise, Python won't have created it yet, so it can't be called.
  • The last way is the normal way for whatever we consider a "script", i.e. something we want to run directly. That's because otherwise we have to rely on `import`ing the code, which has a different meaning from what we're trying to express. Letting the script call the function itself is also more "automatic"; the user doesn't have to take a second step to use the code, and doesn't have to know what the function is called.
  • Of course, it's also possible to just put a bunch of un-indented code in `myscript.py`, and not bother with a function. However, keeping the main part of the code inside a function will be better in the long run for organizational purposes.
  • <details>
  • <summary>Preventing code from running on import</summary>
  • Many real-world scripts contain code along the lines of:
  • ```python
  • if __name__ == '__main__':
  • sys.exit(main())
  • ```
  • There are many variations of this technique, and the use of `sys.exit` is not important for us at the moment. The interesting idea here is the `if` block.
  • Sometimes people talk about this code as if it defined an "entry point" for the script. But this is not accurate. The code still runs from the top to the bottom (defining global variables and classes and functions along the way). What actually happens here is that the code is "guarded", so that the `main` function is only called when the script is run as a script. When the code is simply `import`ed from somewhere else, this code won't run.
  • Why?
  • This happens because of how the special variable `__name__` works. A key idea here is that Python's "global" variables aren't global to an entire program, but only to a file or module. When Python imports a module, it runs the code in that file, using a separate lookup for its global variables; then those global variables become the *attributes* of the module (which is what lets us write things like `mymodule.my_function` after `import mymodule`).
  • Python also sets some special global variables, one of which is `__name__`. When the file was `import`ed as a module, this will be set based on the file name (without the `.py` extension). But when the file is run as a script, `__name__` gets the special value `'__main__'`. Therefore, we can simply test for this value in the `if` statement.
  • </details>
  • ## Starting up Python
  • There are several key ways to use the `python` command from the command line:
  • * `python` by itself starts a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) that allows typing in and running Python code on the fly, one statement at a time.
  • * `python myscript.py` runs the code in `myscript.py`, assuming it's in the current directory. Python will not search for the file to run; the path needs to be given explicitly on the command line.
  • * `python -c "code here"` treats the text supplied as a `-c` argument as Python code and runs it directly. (This example will report a `SyntaxError`, because `code here` is not valid Python code.)
  • * `python -m myscript` tries to find a *module named* `myscript` and run it.
  • Finally, when using one of the latter three methods, it's also possible to pass the `-i` ("interactive") flag. This makes Python start up a REPL *after* running the other specified code, and any global variables from that code will be available in the interpreter.
  • ### Understanding the `-m` flag
  • <details><summary>
  • Using `python -m` to run the code differs from giving a file name or path in several ways:
  • </summary>
  • * The supplied name needs to be a *module* path, the way it would look in an absolute `import` statement inside the code. Since we would import `myscript.py` (assuming everything else were set up properly) using something like `import myscript` (with no `.py`), that's how the command looks: `python -m myscript` (with no `.py`).
  • * This changes the rules for where Python looks for modules. If for example we had `myscript.py` inside of `myfolder`, then `python -m myfolder.myscript` tell Python that *the current directory (`.`) is a place that may contain modules and packages. But `python myfolder/myscript.py` will tell Python that *the `myfolder` directory* is a place that may contain modules and packages.
  • * Python will *search for* the named module, instead of following a specific file path. This is important because some standard library modules (and possibly some third-party packages) offer their own command-line interface, and can be run like scripts instead of just importing them from one's own code.
  • * Starting the code this way will also import packages for folders along the way: `python -m myfolder.myscript` will make `myfolder` a package (and run code in `myfolder/__init__.py`, if there is such a file). This also allows relative imports to work.
  • </details>
  • ## Where code starts running
  • <details><summary>Background understanding</summary>
  • It's important to understand that from Python's perspective, running a script is not much different from importing a module. Either way, the code is run *from top to bottom* in the file. **Any code that isn't indented happens immediately, in order.** (Some code that *is* indented might still happen: for example, code inside an `if` block would run if the condition is satisfied.) This includes things like `import` statements, by the way: they aren't required to be at the top of the file (although this is *usually a good idea*), and they happen when Python encounters them, not automatically.
  • Keep in mind that this does *not* mean that functions are called: "running" the code in the question simply *creates* the function - it doesn't make the code inside the function run.
  • There are **no "special" function names** here. Python won't automatically call a function named `main`, or anything else - functions only run when they are called.
  • Sometimes, you may want to *avoid* having top-level code run - for example, because the file will be both run as a script, and `import`ed from somewhere else. In this case you can [use the `if __name__ == '__main__':` idiom](https://software.codidact.com/posts/291752).
  • </details>
  • ### Strategies for calling `my_function`
  • Therefore, in order for `my_function` to run in the example code, there has to be a call like `my_function()` somewhere. There are a few ways to make this happen:
  • * Start the interpreter like `python`; then use the REPL to `import myscript` and call `myscript.my_function()`. (Or similar ideas, like using `from myscript import my_function` and then `my_function()`.)
  • * Use `python -c` to specify similar code: `python -c "import myscript; myscript.my_function()"`.
  • * Add code like `my_function()` "at top level", so that it runs immediately, and calls the function. Keep in mind that *the function has to appear first in the file* - otherwise, Python won't have created it yet, so it can't be called.
  • The last way is the normal way for whatever we consider a "script", i.e. something we want to run directly. That's because otherwise we have to rely on `import`ing the code, which has a different meaning from what we're trying to express. Letting the script call the function itself is also more "automatic"; the user doesn't have to take a second step to use the code, and doesn't have to know what the function is called.
  • Of course, it's also possible to just put a bunch of un-indented code in `myscript.py`, and not bother with a function. However, keeping the main part of the code inside a function will be better in the long run for organizational purposes.
#2: Post edited by user avatar Karl Knechtel‭ · 2024-06-14T09:57:38Z (6 months ago)
rm content that will be moved to a separate Q&A
  • ## Starting up Python
  • There are several key ways to use the `python` command from the command line:
  • * `python` by itself starts a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) that allows typing in and running Python code on the fly, one statement at a time.
  • * `python myscript.py` runs the code in `myscript.py`, assuming it's in the current directory. Python will not search for the file to run; the path needs to be given explicitly on the command line.
  • * `python -c "code here"` treats the text supplied as a `-c` argument as Python code and runs it directly. (This example will report a `SyntaxError`, because `code here` is not valid Python code.)
  • * `python -m myscript` tries to find a *module named* `myscript` and run it.
  • Finally, when using one of the latter three methods, it's also possible to pass the `-i` ("interactive") flag. This makes Python start up a REPL *after* running the other specified code, and any global variables from that code will be available in the interpreter.
  • ### Understanding the `-m` flag
  • <details><summary>
  • Using `python -m` to run the code differs from giving a file name or path in several ways:
  • </summary>
  • * The supplied name needs to be a *module* path, the way it would look in an absolute `import` statement inside the code. Since we would import `myscript.py` (assuming everything else were set up properly) using something like `import myscript` (with no `.py`), that's how the command looks: `python -m myscript` (with no `.py`).
  • * This changes the rules for where Python looks for modules. If for example we had `myscript.py` inside of `myfolder`, then `python -m myfolder.myscript` tell Python that *the current directory (`.`) is a place that may contain modules and packages. But `python myfolder/myscript.py` will tell Python that *the `myfolder` directory* is a place that may contain modules and packages.
  • * Python will *search for* the named module, instead of following a specific file path. This is important because some standard library modules (and possibly some third-party packages) offer their own command-line interface, and can be run like scripts instead of just importing them from one's own code.
  • * Starting the code this way will also import packages for folders along the way: `python -m myfolder.myscript` will make `myfolder` a package (and run code in `myfolder/__init__.py`, if there is such a file). This also allows relative imports to work.
  • </details>
  • ## Where code starts running
  • <details><summary>Background understanding</summary>
  • It's important to understand that from Python's perspective, running a script is not much different from importing a module. Either way, the code is run *from top to bottom* in the file. **Any code that isn't indented happens immediately, in order.** (Some code that *is* indented might still happen: for example, code inside an `if` block would run if the condition is satisfied.) This includes things like `import` statements, by the way: they aren't required to be at the top of the file (although this is *usually a good idea*), and they happen when Python encounters them, not automatically.
  • Keep in mind that this does *not* mean that functions are called: "running" the code in the question simply *creates* the function - it doesn't make the code inside the function run.
  • There are **no "special" function names** here. Python won't automatically call a function named `main`, or anything else - functions only run when they are called.
  • </details>
  • ### Strategies for calling `my_function`
  • Therefore, in order for `my_function` to run in the example code, there has to be a call like `my_function()` somewhere. There are a few ways to make this happen:
  • * Start the interpreter like `python`; then use the REPL to `import myscript` and call `myscript.my_function()`. (Or similar ideas, like using `from myscript import my_function` and then `my_function()`.)
  • * Use `python -c` to specify similar code: `python -c "import myscript; myscript.my_function()"`.
  • * Add code like `my_function()` "at top level", so that it runs immediately, and calls the function. Keep in mind that *the function has to appear first in the file* - otherwise, Python won't have created it yet, so it can't be called.
  • The last way is the normal way for whatever we consider a "script", i.e. something we want to run directly. That's because otherwise we have to rely on `import`ing the code, which has a different meaning from what we're trying to express. Letting the script call the function itself is also more "automatic"; the user doesn't have to take a second step to use the code, and doesn't have to know what the function is called.
  • Of course, it's also possible to just put a bunch of un-indented code in `myscript.py`, and not bother with a function. However, keeping the main part of the code inside a function will be better in the long run for organizational purposes.
  • <details>
  • <summary>Preventing code from running on import</summary>
  • Many real-world scripts contain code along the lines of:
  • ```python
  • if __name__ == '__main__':
  • sys.exit(main())
  • ```
  • There are many variations of this technique, and the use of `sys.exit` is not important for us at the moment. The interesting idea here is the `if` block.
  • Sometimes people talk about this code as if it defined an "entry point" for the script. But this is not accurate. The code still runs from the top to the bottom (defining global variables and classes and functions along the way). What actually happens here is that the code is "guarded", so that the `main` function is only called when the script is run as a script. When the code is simply `import`ed from somewhere else, this code won't run.
  • Why?
  • This happens because of how the special variable `__name__` works. A key idea here is that Python's "global" variables aren't global to an entire program, but only to a file or module. When Python imports a module, it runs the code in that file, using a separate lookup for its global variables; then those global variables become the *attributes* of the module (which is what lets us write things like `mymodule.my_function` after `import mymodule`).
  • Python also sets some special global variables, one of which is `__name__`. When the file was `import`ed as a module, this will be set based on the file name (without the `.py` extension). But when the file is run as a script, `__name__` gets the special value `'__main__'`. Therefore, we can simply test for this value in the `if` statement.
  • </details>
  • ## Making scripts run themselves
  • Sometimes people want to make Python scripts "executable", so that they can be used directly from the command line without writing `python` (or by double-clicking them in a file explorer). This is operating system-dependent.
  • <details><summary>Mac/Linux</summary>
  • In this environment, Python scripts can be given a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) line that tells the operating system that the file is a script, and what interpreter (i.e., Python) to use for it. Because `#` starts a comment in Python, Python itself doesn't need any special handling for this - it's just ignored anyway. Of course, the file also needs to be marked as executable (`chmod +x`).
  • Keep in mind that without a shebang, the operating system will typically try to treat the script as a *shell* script, which will fail completely (probably with many errors). The operating system doesn't care about a `.py` extension on the file name.
  • It's common to use something like `#!/usr/bin/env python`, to allow the operating system to find Python. But sometimes it's necessary to give the path to a specific Python to make the script work properly.
  • It's also common for such scripts to name the file *without* a `.py` extension (so just `myscript`), and to *not* use a `if __name__ == '__main__:` guard. That's because these tools are simply unnecessary if the script will *only* be used as a script and *should not* ever be `import`ed from somewhere else.
  • Let's see how a complete example looks in a typical Linux shell.
  • How the script is named, and the permissions:
  • ```lang-none
  • $ ls
  • myscript
  • $ stat -c '%A' myscript
  • -rwxrwxr-x
  • ```
  • What's in it:
  • ```python
  • $ cat myscript
  • #!/usr/bin/env python
  • def my_function():
  • print("Test")
  • my_function()
  • ```
  • How we run it, and what happens:
  • ```lang-none
  • $ ./myscript
  • Test
  • ```
  • </details><details><summary>Windows</summary>
  • Windows does not care about shebangs generally, and doesn't have a concept of executable text files. However, it does have a concept of file associations - so we can tell Windows to use Python (via a specific path to `python`, perhaps something like<br>`C:\Program Files\Python 3.12\python.exe`) to open any file with a `.py` file name extension when it's double-clicked.
  • But better yet, we can tell it to use [the Python Launcher for Windows](https://docs.python.org/3/using/windows.html#python-launcher-for-windows). There's only one of these even if you install multiple versions of Python, and it's in a single, consistent place -<br>`C:\Windows\py.exe` (assuming Python was installed "for all users"). More importantly, this `py` program *tries to read and understand shebang lines* - simply write the script *as if* it would run on a Mac or Linux system, and let `py` do the rest.
  • </details>
  • ## Starting up Python
  • There are several key ways to use the `python` command from the command line:
  • * `python` by itself starts a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) that allows typing in and running Python code on the fly, one statement at a time.
  • * `python myscript.py` runs the code in `myscript.py`, assuming it's in the current directory. Python will not search for the file to run; the path needs to be given explicitly on the command line.
  • * `python -c "code here"` treats the text supplied as a `-c` argument as Python code and runs it directly. (This example will report a `SyntaxError`, because `code here` is not valid Python code.)
  • * `python -m myscript` tries to find a *module named* `myscript` and run it.
  • Finally, when using one of the latter three methods, it's also possible to pass the `-i` ("interactive") flag. This makes Python start up a REPL *after* running the other specified code, and any global variables from that code will be available in the interpreter.
  • ### Understanding the `-m` flag
  • <details><summary>
  • Using `python -m` to run the code differs from giving a file name or path in several ways:
  • </summary>
  • * The supplied name needs to be a *module* path, the way it would look in an absolute `import` statement inside the code. Since we would import `myscript.py` (assuming everything else were set up properly) using something like `import myscript` (with no `.py`), that's how the command looks: `python -m myscript` (with no `.py`).
  • * This changes the rules for where Python looks for modules. If for example we had `myscript.py` inside of `myfolder`, then `python -m myfolder.myscript` tell Python that *the current directory (`.`) is a place that may contain modules and packages. But `python myfolder/myscript.py` will tell Python that *the `myfolder` directory* is a place that may contain modules and packages.
  • * Python will *search for* the named module, instead of following a specific file path. This is important because some standard library modules (and possibly some third-party packages) offer their own command-line interface, and can be run like scripts instead of just importing them from one's own code.
  • * Starting the code this way will also import packages for folders along the way: `python -m myfolder.myscript` will make `myfolder` a package (and run code in `myfolder/__init__.py`, if there is such a file). This also allows relative imports to work.
  • </details>
  • ## Where code starts running
  • <details><summary>Background understanding</summary>
  • It's important to understand that from Python's perspective, running a script is not much different from importing a module. Either way, the code is run *from top to bottom* in the file. **Any code that isn't indented happens immediately, in order.** (Some code that *is* indented might still happen: for example, code inside an `if` block would run if the condition is satisfied.) This includes things like `import` statements, by the way: they aren't required to be at the top of the file (although this is *usually a good idea*), and they happen when Python encounters them, not automatically.
  • Keep in mind that this does *not* mean that functions are called: "running" the code in the question simply *creates* the function - it doesn't make the code inside the function run.
  • There are **no "special" function names** here. Python won't automatically call a function named `main`, or anything else - functions only run when they are called.
  • </details>
  • ### Strategies for calling `my_function`
  • Therefore, in order for `my_function` to run in the example code, there has to be a call like `my_function()` somewhere. There are a few ways to make this happen:
  • * Start the interpreter like `python`; then use the REPL to `import myscript` and call `myscript.my_function()`. (Or similar ideas, like using `from myscript import my_function` and then `my_function()`.)
  • * Use `python -c` to specify similar code: `python -c "import myscript; myscript.my_function()"`.
  • * Add code like `my_function()` "at top level", so that it runs immediately, and calls the function. Keep in mind that *the function has to appear first in the file* - otherwise, Python won't have created it yet, so it can't be called.
  • The last way is the normal way for whatever we consider a "script", i.e. something we want to run directly. That's because otherwise we have to rely on `import`ing the code, which has a different meaning from what we're trying to express. Letting the script call the function itself is also more "automatic"; the user doesn't have to take a second step to use the code, and doesn't have to know what the function is called.
  • Of course, it's also possible to just put a bunch of un-indented code in `myscript.py`, and not bother with a function. However, keeping the main part of the code inside a function will be better in the long run for organizational purposes.
  • <details>
  • <summary>Preventing code from running on import</summary>
  • Many real-world scripts contain code along the lines of:
  • ```python
  • if __name__ == '__main__':
  • sys.exit(main())
  • ```
  • There are many variations of this technique, and the use of `sys.exit` is not important for us at the moment. The interesting idea here is the `if` block.
  • Sometimes people talk about this code as if it defined an "entry point" for the script. But this is not accurate. The code still runs from the top to the bottom (defining global variables and classes and functions along the way). What actually happens here is that the code is "guarded", so that the `main` function is only called when the script is run as a script. When the code is simply `import`ed from somewhere else, this code won't run.
  • Why?
  • This happens because of how the special variable `__name__` works. A key idea here is that Python's "global" variables aren't global to an entire program, but only to a file or module. When Python imports a module, it runs the code in that file, using a separate lookup for its global variables; then those global variables become the *attributes* of the module (which is what lets us write things like `mymodule.my_function` after `import mymodule`).
  • Python also sets some special global variables, one of which is `__name__`. When the file was `import`ed as a module, this will be set based on the file name (without the `.py` extension). But when the file is run as a script, `__name__` gets the special value `'__main__'`. Therefore, we can simply test for this value in the `if` statement.
  • </details>
#1: Initial revision by user avatar Karl Knechtel‭ · 2024-04-20T22:53:19Z (8 months ago)
## Starting up Python

There are several key ways to use the `python` command from the command line:

* `python` by itself starts a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) that allows typing in and running Python code on the fly, one statement at a time.

* `python myscript.py` runs the code in `myscript.py`, assuming it's in the current directory. Python will not search for the file to run; the path needs to be given explicitly on the command line.

* `python -c "code here"` treats the text supplied as a `-c` argument as Python code and runs it directly. (This example will report a `SyntaxError`, because `code here` is not valid Python code.)

* `python -m myscript` tries to find a *module named* `myscript` and run it.

Finally, when using one of the latter three methods, it's also possible to pass the `-i` ("interactive") flag. This makes Python start up a REPL *after* running the other specified code, and any global variables from that code will be available in the interpreter.

### Understanding the `-m` flag

<details><summary>

Using `python -m` to run the code differs from giving a file name or path in several ways:
</summary>

  * The supplied name needs to be a *module* path, the way it would look in an absolute `import` statement inside the code. Since we would import `myscript.py` (assuming everything else were set up properly) using something like `import myscript` (with no `.py`), that's how the command looks: `python -m myscript` (with no `.py`).

  * This changes the rules for where Python looks for modules. If for example we had `myscript.py` inside of `myfolder`, then `python -m myfolder.myscript` tell Python that *the current directory (`.`) is a place that may contain modules and packages. But `python myfolder/myscript.py` will tell Python that *the `myfolder` directory* is a place that may contain modules and packages.

  * Python will *search for* the named module, instead of following a specific file path. This is important because some standard library modules (and possibly some third-party packages) offer their own command-line interface, and can be run like scripts instead of just importing them from one's own code.

  * Starting the code this way will also import packages for folders along the way: `python -m myfolder.myscript` will make `myfolder` a package (and run code in `myfolder/__init__.py`, if there is such a file). This also allows relative imports to work.
</details>

## Where code starts running

<details><summary>Background understanding</summary>

It's important to understand that from Python's perspective, running a script is not much different from importing a module. Either way, the code is run *from top to bottom* in the file. **Any code that isn't indented happens immediately, in order.** (Some code that *is* indented might still happen: for example, code inside an `if` block would run if the condition is satisfied.) This includes things like `import` statements, by the way: they aren't required to be at the top of the file (although this is *usually a good idea*), and they happen when Python encounters them, not automatically.

Keep in mind that this does *not* mean that functions are called: "running" the code in the question simply *creates* the function - it doesn't make the code inside the function run.

There are **no "special" function names** here. Python won't automatically call a function named `main`, or anything else - functions only run when they are called.
</details>

### Strategies for calling `my_function`

Therefore, in order for `my_function` to run in the example code, there has to be a call like `my_function()` somewhere. There are a few ways to make this happen:

* Start the interpreter like `python`; then use the REPL to `import myscript` and call `myscript.my_function()`. (Or similar ideas, like using `from myscript import my_function` and then `my_function()`.)

* Use `python -c` to specify similar code: `python -c "import myscript; myscript.my_function()"`.

* Add code like `my_function()` "at top level", so that it runs immediately, and calls the function. Keep in mind that *the function has to appear first in the file* - otherwise, Python won't have created it yet, so it can't be called.

The last way is the normal way for whatever we consider a "script", i.e. something we want to run directly. That's because otherwise we have to rely on `import`ing the code, which has a different meaning from what we're trying to express. Letting the script call the function itself is also more "automatic"; the user doesn't have to take a second step to use the code, and doesn't have to know what the function is called.

Of course, it's also possible to just put a bunch of un-indented code in `myscript.py`, and not bother with a function. However, keeping the main part of the code inside a function will be better in the long run for organizational purposes.

<details>
<summary>Preventing code from running on import</summary>

Many real-world scripts contain code along the lines of:

```python
if __name__ == '__main__':
    sys.exit(main())
```

There are many variations of this technique, and the use of `sys.exit` is not important for us at the moment. The interesting idea here is the `if` block.

Sometimes people talk about this code as if it defined an "entry point" for the script. But this is not accurate. The code still runs from the top to the bottom (defining global variables and classes and functions along the way). What actually happens here is that the code is "guarded", so that the `main` function is only called when the script is run as a script. When the code is simply `import`ed from somewhere else, this code won't run.

Why?

This happens because of how the special variable `__name__` works. A key idea here is that Python's "global" variables aren't global to an entire program, but only to a file or module. When Python imports a module, it runs the code in that file, using a separate lookup for its global variables; then those global variables become the *attributes* of the module (which is what lets us write things like `mymodule.my_function` after `import mymodule`).

Python also sets some special global variables, one of which is `__name__`. When the file was `import`ed as a module, this will be set based on the file name (without the `.py` extension). But when the file is run as a script, `__name__` gets the special value `'__main__'`. Therefore, we can simply test for this value in the `if` statement.
</details>

## Making scripts run themselves

Sometimes people want to make Python scripts "executable", so that they can be used directly from the command line without writing `python` (or by double-clicking them in a file explorer). This is operating system-dependent.

<details><summary>Mac/Linux</summary>

In this environment, Python scripts can be given a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) line that tells the operating system that the file is a script, and what interpreter (i.e., Python) to use for it. Because `#` starts a comment in Python, Python itself doesn't need any special handling for this - it's just ignored anyway. Of course, the file also needs to be marked as executable (`chmod +x`).

Keep in mind that without a shebang, the operating system will typically try to treat the script as a *shell* script, which will fail completely (probably with many errors). The operating system doesn't care about a `.py` extension on the file name.

It's common to use something like `#!/usr/bin/env python`, to allow the operating system to find Python. But sometimes it's necessary to give the path to a specific Python to make the script work properly.

It's also common for such scripts to name the file *without* a `.py` extension (so just `myscript`), and to *not* use a `if __name__ == '__main__:` guard. That's because these tools are simply unnecessary if the script will *only* be used as a script and *should not* ever be `import`ed from somewhere else.

Let's see how a complete example looks in a typical Linux shell.

How the script is named, and the permissions:
```lang-none
$ ls
myscript
$ stat -c '%A' myscript 
-rwxrwxr-x
```
What's in it:
```python
$ cat myscript 
#!/usr/bin/env python

def my_function():
    print("Test")

my_function()
```
How we run it, and what happens:
```lang-none
$ ./myscript 
Test
```
</details><details><summary>Windows</summary>

Windows does not care about shebangs generally, and doesn't have a concept of executable text files. However, it does have a concept of file associations - so we can tell Windows to use Python (via a specific path to `python`, perhaps something like<br>`C:\Program Files\Python 3.12\python.exe`) to open any file with a `.py` file name extension when it's double-clicked.

But better yet, we can tell it to use [the Python Launcher for Windows](https://docs.python.org/3/using/windows.html#python-launcher-for-windows). There's only one of these even if you install multiple versions of Python, and it's in a single, consistent place -<br>`C:\Windows\py.exe` (assuming Python was installed "for all users"). More importantly, this `py` program *tries to read and understand shebang lines* - simply write the script *as if* it would run on a Mac or Linux system, and let `py` do the rest.
</details>