Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions python-program-structure/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Python Program Lexical Structure

This folder provides the code examples for the Real Python tutorial [Python Program Lexical Structure](https://realpython.com/python-program-structure/).

You can run all of the scripts directly by specifying their name:

```sh
$ python <filename>.py
```

The scripts only use the standard library, so there's nothing to install.

## The Scripts

Each script collects one section of the tutorial, in the order the tutorial presents it:

| Script | Tutorial section |
| --- | --- |
| [`statements.py`](./statements.py) | Python Statements |
| [`long_statements.py`](./long_statements.py) | Line Continuation |
| [`implicit_line_continuation.py`](./implicit_line_continuation.py) | Implicit Line Continuation |
| [`explicit_line_continuation.py`](./explicit_line_continuation.py) | Explicit Line Continuation |
| [`multiple_statements.py`](./multiple_statements.py) | Multiple Statements Per Line |
| [`comments.py`](./comments.py) | Comments |
| [`foo.py`](./foo.py) | Comments (the script file shown in the tutorial) |
| [`whitespace.py`](./whitespace.py) | Whitespace |

## A Note on the Examples

Nearly all of the tutorial's examples are REPL sessions. They've been turned into runnable scripts here, which means two small changes:

- Where the REPL echoed a value, the script calls `print()` so that you see the same result. String values are printed with `repr()` so that the output matches the quoted form the REPL displays.
- The code is otherwise copied verbatim, including the tutorial's single quotes and its deliberately cramped or deliberately sprawling line layouts.

That second point is why every script switches the formatter off with `# fmt: off`. This tutorial is *about* lexical structure, so line layout, whitespace, and quoting are the subject matter. Reformatting the examples would join the continued lines, split the semicolons, and pad out the whitespace, which would delete the very thing each example is demonstrating. For the same reason, the two semicolon examples carry a `# noqa: E702`.

The tutorial also shows a number of deliberate errors: unterminated statements, a backslash followed by a space, `sin`, `is20`, `notin`, and an unexpected indent. Those blocks can't run, so they aren't reproduced as code. Each script's docstring names the ones its section skips.

The tutorial's final code section, "Whitespace as Indentation," is not represented by a script. Its only Python example is a single `print('foo')` call and an `IndentationError`.
58 changes: 58 additions & 0 deletions python-program-structure/comments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Attaching explanatory detail to code with the hash character.

Code from the "Comments" section of the tutorial. The interpreter ignores
everything from a '#' to the end of that line, unless the '#' is inside a
string literal.

The tutorial's backslash-plus-comment example is not reproduced here: a
comment cannot follow an explicit line continuation, so it raises a
SyntaxError.
"""

# fmt: off
a = ['foo', 'bar', 'baz'] # I am a comment.
print(a)

# I am a comment.
# I am too.

# A hash inside a string literal is protected and starts no comment.
a = 'foobar # I am *not* a comment.'
print(repr(a))

# Calculate and display the area of a circle.

pi = 3.1415926536
r = 12.35

area = pi * (r ** 2)

print('The area of a circle with radius', r, 'is', area)

# Comments can be included within implicit line continuation.
x = (1 + 2 # I am a comment.
+ 3 + 4 # Me too.
+ 5 + 6)
print(x)

a = [
'foo', 'bar', # Me three.
'baz', 'qux'
]
print(a)

# Python has no block comment syntax, so a multiline comment is just a run
# of hash-prefixed lines:

# Initialize value for radius of circle.
#
# Then calculate the area of the circle
# and display the result to the console.

pi = 3.1415926536
r = 12.35

area = pi * (r ** 2)

print('The area of a circle with radius', r, 'is', area)
# fmt: on
22 changes: 22 additions & 0 deletions python-program-structure/explicit_line_continuation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Continuing a statement across lines with a backslash.

Code from the "Explicit Line Continuation" section of the tutorial. A
backslash as the very last character on a line tells Python to ignore the
newline that follows it. PEP 8 recommends reaching for this only when
implicit line continuation is not practicable.

The tutorial's three error examples are not reproduced here because they
cannot run: an unterminated 's =', an unterminated 'x = 1 + 2 +', and a
backslash followed by a stray space character.
"""

# fmt: off
s = \
'Hello, World!'
print(repr(s))

x = 1 + 2 \
+ 3 + 4 \
+ 5 + 6
print(x)
# fmt: on
14 changes: 14 additions & 0 deletions python-program-structure/foo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# fmt: off
"""Initialize value for radius of circle.

Then calculate the area of the circle
and display the result to the console.
"""

pi = 3.1415926536
r = 12.35

area = pi * (r ** 2)

print('The area of a circle with radius', r, 'is', area)
# fmt: on
116 changes: 116 additions & 0 deletions python-program-structure/implicit_line_continuation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""Continuing a statement across lines with parentheses, brackets, or braces.

Code from the "Implicit Line Continuation" section of the tutorial, in the
order the tutorial presents it. Any statement with an open '(', '[', or '{'
is presumed incomplete until the matching closer is found, so it can run on
across as many lines as you like.

The blocks that only define a value are given a print() here so that
running the script shows you the result.
"""

# fmt: off
person1_age = 42
person2_age = 16
person3_age = 71

# The nested list from the previous section, made readable by the open
# brackets.
a = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]
]
print(a)

# A long expression wrapped in grouping parentheses, as PEP 8 advocates.
someone_is_of_working_age = (
(person1_age >= 18 and person1_age <= 65)
or (person2_age >= 18 and person2_age <= 65)
or (person3_age >= 18 and person3_age <= 65)
)
print(someone_is_of_working_age)

# Parentheses: expression grouping
x = (
1 + 2
+ 3 + 4
+ 5 + 6
)
print(x)

# Parentheses: function call
print(
'foo',
'bar',
'baz'
)

# Parentheses: method call
print(repr('abc'.center(
9,
'-'
)))

# Parentheses: tuple definition
t = (
'a', 'b',
'c', 'd'
)
print(t)

# Curly braces: dictionary definition
d = {
'a': 1,
'b': 2
}
print(d)

# Curly braces: set definition
x1 = {
'foo',
'bar',
'baz'
}
# Deliberately not printed: the display order of a set of strings varies
# between runs, and the tutorial shows no output for this block either.

# Square brackets: list definition
a = [
'foo', 'bar',
'baz', 'qux'
]
print(a)

# Square brackets: indexing
print(repr(a[
1
]))

# Square brackets: slicing
print(a[
1:2
])

# Square brackets: dictionary key reference
print(d[
'b'
])

# Implicit continuation stays in effect until every parenthesis, bracket,
# and brace has been closed. Indentation clarifies the nested structure.
a = [
[
['foo', 'bar'],
[1, 2, 3]
],
{1, 3, 5},
{
'a': 1,
'b': 2
}
]
print(a)
# fmt: on
21 changes: 21 additions & 0 deletions python-program-structure/long_statements.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Statements that grow too long to read comfortably on one line.

Code from the "Line Continuation" section of the tutorial: these are the
"before" examples that motivate implicit and explicit line continuation.
The excessive line lengths are deliberate.

The tutorial also shows an unterminated statement that raises a
SyntaxError. That block is not reproduced here because it cannot run.
"""

# fmt: off
person1_age = 42
person2_age = 16
person3_age = 71

someone_is_of_working_age = (person1_age >= 18 and person1_age <= 65) or (person2_age >= 18 and person2_age <= 65) or (person3_age >= 18 and person3_age <= 65)
print(someone_is_of_working_age)

a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25]]
print(a)
# fmt: on
16 changes: 16 additions & 0 deletions python-program-structure/multiple_statements.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Putting several statements on one line with semicolons.

Code from the "Multiple Statements Per Line" section of the tutorial.
Python allows it, PEP 8 expressly discourages it, and Ruff flags it as
E702 -- which is exactly the tutorial's point, so the warnings are
suppressed rather than the examples rewritten.
"""

# fmt: off
x = 1; y = 2; z = 3 # noqa: E702
print(x); print(y); print(z) # noqa: E702

# The same result, written the way a Python programmer normally would.
x, y, z = 1, 2, 3
print(x, y, z, sep='\n')
# fmt: on
19 changes: 19 additions & 0 deletions python-program-structure/statements.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Statements, the basic units of instruction in a Python program.

Code from the "Python Statements" section of the tutorial.

The formatter is switched off in this folder on purpose: this tutorial is
about lexical structure, so the exact line layout, whitespace, and quoting
of every example below is the lesson, not incidental style.
"""

# fmt: off
print('Hello, World!')

x = [1, 2, 3]
print(x[1:2])

# At the REPL a bare expression displays its value. In a script file it does
# nothing at all, so you need print() to see the result.
print(repr('foobar'[2:5]))
# fmt: on
61 changes: 61 additions & 0 deletions python-program-structure/whitespace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Where whitespace matters to the interpreter, and where it matters to you.

Code from the "Whitespace" section of the tutorial. Whitespace is mostly
optional between tokens, but leaving it out hurts readability, and it
becomes mandatory when it is the only thing separating an identifier from
a keyword.

The cramped examples below are copied from the tutorial verbatim. They are
not code you should write.

Three error examples from the tutorial are not reproduced here because they
cannot run: 'sin [...]' raises a NameError, and 'y is20' and "'qux' notin
[...]" both raise a SyntaxError.
"""

# fmt: off
# No whitespace at all -- the interpreter handles all of these fine.
x=3;y=12 # noqa: E702
print(x+y)

print((x==3)and(x<y))

a=['foo','bar','baz']
print(a)

d={'foo':3,'bar':4}
print(d)

x,y,z='foo',14,21.1
print((x,y,z))

z='foo'"bar"'baz'#Comment
print(repr(z))

# Compare these two fragments. Most people find the second easier to read.
value1=100
value2=200
v=(value1>=0)and(value1<value2)
print(v)

value1 = 100
value2 = 200
v = (value1 >= 0) and (value1 < value2)
print(v)

# String literals can be juxtaposed with or without whitespace. The effect
# is concatenation, exactly as though you had used the + operator.
s = "foo"'bar''''baz'''
print(repr(s))

s = 'foo' "bar" '''baz'''
print(repr(s))

# Whitespace is required here to separate the identifier s from the
# keyword in, and to separate the keywords not and in.
s = 'bar'

print(s in ['foo', 'bar', 'baz'])

print('qux' not in ['foo', 'bar', 'baz'])
# fmt: on
Loading