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.

How and where does Python code start running? How can I control that?

+2
−0

Suppose I have some code in a file myscript.py like:

def my_function():
    print("Test")

What steps do I need to take in order to make my_function run? That is to say: how do I get Python to run myscript.py; and from there, how do I choose my_function as the starting point for the code? In particular, do I need to use a specific name for my starting function (such as main, as seen in some other programming languages)?

History
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

1 comment thread

Background and intended scope (2 comments)

2 answers

+1
−0

Files with .py extension are scripts. You run them with python myscript.py.

Python is an imperative language, so executing a file will run each line one by one, starting from the top, and exit when the end of the file is reached.

In your example, the script is saying:

  1. Create a function called my_function
  2. This function, when called, will print some text

Notice we're telling Python to create the function, but we never tell it to call that function. Your example will appear to do nothing when executed (well, it may briefly waste some memory to store this function which never not gets used).

You have two options here, either get rid of the function definition, or add call.

Option 1:

# an actual command, not the content of a function definition
print("Test")

Option 2:

# define a function
def my_function():
    print("Test")

# actually execute the function
my_function()
History
Why does this post require moderator attention?
You might want to add some details to your flag.

0 comment threads

+1
−0

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 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

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

  • 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.

Where code starts running

Background understanding

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.

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 importing 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.

Preventing code from running on import

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

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 imported 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 imported 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.

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.

Mac/Linux

In this environment, Python scripts can be given a shebang 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 imported from somewhere else.

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

How the script is named, and the permissions:

$ ls
myscript
$ stat -c '%A' myscript 
-rwxrwxr-x

What's in it:

$ cat myscript 
#!/usr/bin/env python

def my_function():
    print("Test")

my_function()

How we run it, and what happens:

$ ./myscript 
Test
Windows

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
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. There's only one of these even if you install multiple versions of Python, and it's in a single, consistent place -
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.

History
Why does this post require moderator attention?
You might want to add some details to your flag.

1 comment thread

Split up answer (5 comments)

Sign up to answer this question »