Python syntax and semantics


The syntax of the Python programming language is the set of rules that defines how a Python program will be written and interpreted. The Python language has many similarities to Perl, C, and Java. However, there are some definite differences between the languages. It supports multiple programming paradigms, including structured, object-oriented programming, and functional programming, and boasts a dynamic type system and automatic memory management.
Python's syntax is simple and consistent, adhering to the principle that "There should be one—and preferably only one—obvious way to do it." The language incorporates built-in data types and structures, control flow mechanisms, first-class functions, and modules for better code reusability and organization. Python also uses English keywords where other languages use punctuation, contributing to its uncluttered visual layout.
The language provides robust error handling through exceptions, and includes a debugger in the standard library for efficient problem-solving. Python's syntax, designed for readability and ease of use, makes it a popular choice among beginners and professionals alike.

Design philosophy

Python was designed to be a highly readable language. It has a relatively uncluttered visual layout and uses English keywords frequently where other languages use punctuation. Python aims to be simple and consistent in the design of its syntax, encapsulated in the mantra, from the Zen of Python.
This mantra is deliberately opposed to the Perl and Ruby mantra, "there's more than one way to do it".

Keywords

Python 3 has 35 keywords or reserved words; they cannot be used as identifiers.
  • and
  • as
  • assert
  • async
  • await
  • break
  • class
  • continue
  • def
  • del
  • elif
  • else
  • except
  • False
  • finally
  • for
  • from
  • global
  • if
  • import
  • in
  • is
  • lambda
  • None
  • nonlocal
  • not
  • or
  • pass
  • raise
  • return
  • True
  • try
  • while
  • with
  • yield
In addition, Python 3 also has 4 soft keywords, including type added in Python 3.12. Unlike regular hard keywords, soft keywords are reserved words only in the limited contexts where interpreting them as keywords would make syntactic sense. These words can be used as identifiers elsewhere, in other words, match and case are valid names for functions and variables.
  • _
  • case
  • match
  • type

    Function annotations

Function annotations are defined in PEP 3107. They allow attaching data to the arguments and return of a function. The behaviour of annotations is not defined by the language, and is left to third party frameworks. For example, a library could be written to handle static typing:

def haul -> Distance:
# implementation here

While annotations are optional in Python, the rest of this article will use annotations to provide clarity.

Modules and import statements

In Python, code is organized into files called modules, and namespaces are defined by the individual modules. Since modules can be contained in hierarchical packages, then namespaces are hierarchical too.
In general when a module is imported then the names defined in the module are defined via that module's namespace, and are accessed in from the calling modules by using the fully qualified name.

  1. assume ModuleA defines two functions : func1 and func2 and one class : Class1
import ModuleA
ModuleA.func1
ModuleA.func2
a: ModuleA.Class1 = Modulea.Class1

The from... import... statement can be used to insert the relevant names directly into the calling module's namespace, and those names can be accessed from the calling module without the qualified name:

  1. assume ModuleA defines two functions : func1 and func2 and one class : Class1
from ModuleA import func1
func1
func2 # this will fail as an undefined name, as will the full name ModuleA.func2
a: Class1 = Class1 # this will fail as an undefined name, as will the full name ModuleA.Class1

Since this directly imports names it can overwrite existing names with no warnings.
A special form of the statement is from... import * which imports all names defined in the named package directly in the calling module's namespace. Use of this form of import, although supported within the language, is generally discouraged as it pollutes the namespace of the calling module and will cause already defined names to be overwritten in the case of name clashes. However, this page will present code as if the line "from typing import *" were included, for referring to collection types.
The different import statements are demonstrated here:

  1. imports the argument parsing module
import argparse
  1. imports the Pattern class from the regular expressions module
from re import Pattern
  1. imports all symbols inside the typing module
from typing import *

Using from import statements in Python can simplify verbose namespaces, such as nested namespaces.

from selenium.webdriver import Firefox
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.webelement import WebElement
if __name__ "__main__":
driver: Firefox = Firefox
element: WebElement = driver.find_element
element.send_keys
action: ActionChains = ActionChains
action.key_down.send_keys.key_up.perform

Python also supports import x as y as a way of providing an alias or alternative name for use by the calling module:

import numpy as np
from numpy.typing import NDArray, float32
a: NDArray = np.arange

When a module is imported, the Python interpreter first checks if it exists in the sys.modules cache, and reuses it if it had been imported previously, otherwise it loads it. When loading, it searches it in sys.path, and compiles it to bytecode or interprets its contents. All code in the global scope of the module is executed. However, this can be mitigated using an explicit main function, which behaves similarly to an entry point in most compiled languages, using the entry point idiom described as follows.

Entry point

A pseudo-entry point can be created by the following idiom, which relies on the internal variable __name__ being set to __main__ when a program is executed, but not when it is imported as a module ; there are many variants of this structure:

import sys
def main -> int:
argc: int = len # get length of argv
n: int = int
print
return 0
if __name__ "__main__":
sys.exit

In this idiom, the call to the named entry point main is explicit, and the interaction with the operating system are done explicitly by library calls, which are ultimately handled by the Python runtime. This contrasts with C, where these are done implicitly by the runtime, based on convention.

Indentation

Python uses whitespace to delimit control flow blocks. Python borrows this feature from its predecessor ABC: instead of punctuation or keywords, it uses indentation to indicate the run of a block.
In so-called "free-format" languages – that use the block structure derived from ALGOL – blocks of code are set off with braces or keywords. In most coding conventions for these languages, programmers conventionally indent the code within a block, to visually set it apart from the surrounding code.
A recursive function named foo, which is passed a single parameter, x, and if the parameter is 0 will call a different function named bar and otherwise will call baz, passing x, and also call itself recursively, passing x-1 as the parameter, could be implemented like this in Python:

def foo -> None:
if x 0:
bar
else:
baz
foo

and could be written like this in C:

void foo

Incorrectly indented code could be misread by a human reader differently than it would be interpreted by a compiler or interpreter. For example, if the function call foo on the last line in the example above was erroneously indented to be outside the if/else block:

def foo -> None:
if x 0:
bar
else:
baz
foo

it would cause the last line to always be executed, even when x is 0, resulting in an endless recursion.
While both space and tab characters are accepted as forms of indentation and any multiple of spaces can be used, spaces are recommended and four spaces are recommended and are by far the most commonly used. Mixing spaces and tabs on consecutive lines is not allowed starting with Python 3 because that can create bugs which are difficult to see, since many text editors do not visually distinguish spaces and tabs.