Skip to content

Commit d09a3e6

Browse files
Add materials for Python Program Lexical Structure
New companion-code folder for a tutorial that never had one. The article is almost entirely REPL sessions, so each section's sequence became one runnable script that prints its results. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent d867710 commit d09a3e6

9 files changed

Lines changed: 366 additions & 0 deletions

File tree

python-program-structure/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Python Program Lexical Structure
2+
3+
This folder provides the code examples for the Real Python tutorial [Python Program Lexical Structure](https://realpython.com/python-program-structure/).
4+
5+
You can run all of the scripts directly by specifying their name:
6+
7+
```sh
8+
$ python <filename>.py
9+
```
10+
11+
The scripts only use the standard library, so there's nothing to install.
12+
13+
## The Scripts
14+
15+
Each script collects one section of the tutorial, in the order the tutorial presents it:
16+
17+
| Script | Tutorial section |
18+
| --- | --- |
19+
| [`statements.py`](./statements.py) | Python Statements |
20+
| [`long_statements.py`](./long_statements.py) | Line Continuation |
21+
| [`implicit_line_continuation.py`](./implicit_line_continuation.py) | Implicit Line Continuation |
22+
| [`explicit_line_continuation.py`](./explicit_line_continuation.py) | Explicit Line Continuation |
23+
| [`multiple_statements.py`](./multiple_statements.py) | Multiple Statements Per Line |
24+
| [`comments.py`](./comments.py) | Comments |
25+
| [`foo.py`](./foo.py) | Comments (the script file shown in the tutorial) |
26+
| [`whitespace.py`](./whitespace.py) | Whitespace |
27+
28+
## A Note on the Examples
29+
30+
Nearly all of the tutorial's examples are REPL sessions. They've been turned into runnable scripts here, which means two small changes:
31+
32+
- 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.
33+
- The code is otherwise copied verbatim, including the tutorial's single quotes and its deliberately cramped or deliberately sprawling line layouts.
34+
35+
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`.
36+
37+
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.
38+
39+
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`.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Attaching explanatory detail to code with the hash character.
2+
3+
Code from the "Comments" section of the tutorial. The interpreter ignores
4+
everything from a '#' to the end of that line, unless the '#' is inside a
5+
string literal.
6+
7+
The tutorial's backslash-plus-comment example is not reproduced here: a
8+
comment cannot follow an explicit line continuation, so it raises a
9+
SyntaxError.
10+
"""
11+
12+
# fmt: off
13+
a = ['foo', 'bar', 'baz'] # I am a comment.
14+
print(a)
15+
16+
# I am a comment.
17+
# I am too.
18+
19+
# A hash inside a string literal is protected and starts no comment.
20+
a = 'foobar # I am *not* a comment.'
21+
print(repr(a))
22+
23+
# Calculate and display the area of a circle.
24+
25+
pi = 3.1415926536
26+
r = 12.35
27+
28+
area = pi * (r ** 2)
29+
30+
print('The area of a circle with radius', r, 'is', area)
31+
32+
# Comments can be included within implicit line continuation.
33+
x = (1 + 2 # I am a comment.
34+
+ 3 + 4 # Me too.
35+
+ 5 + 6)
36+
print(x)
37+
38+
a = [
39+
'foo', 'bar', # Me three.
40+
'baz', 'qux'
41+
]
42+
print(a)
43+
44+
# Python has no block comment syntax, so a multiline comment is just a run
45+
# of hash-prefixed lines:
46+
47+
# Initialize value for radius of circle.
48+
#
49+
# Then calculate the area of the circle
50+
# and display the result to the console.
51+
52+
pi = 3.1415926536
53+
r = 12.35
54+
55+
area = pi * (r ** 2)
56+
57+
print('The area of a circle with radius', r, 'is', area)
58+
# fmt: on
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""Continuing a statement across lines with a backslash.
2+
3+
Code from the "Explicit Line Continuation" section of the tutorial. A
4+
backslash as the very last character on a line tells Python to ignore the
5+
newline that follows it. PEP 8 recommends reaching for this only when
6+
implicit line continuation is not practicable.
7+
8+
The tutorial's three error examples are not reproduced here because they
9+
cannot run: an unterminated 's =', an unterminated 'x = 1 + 2 +', and a
10+
backslash followed by a stray space character.
11+
"""
12+
13+
# fmt: off
14+
s = \
15+
'Hello, World!'
16+
print(repr(s))
17+
18+
x = 1 + 2 \
19+
+ 3 + 4 \
20+
+ 5 + 6
21+
print(x)
22+
# fmt: on

python-program-structure/foo.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# fmt: off
2+
"""Initialize value for radius of circle.
3+
4+
Then calculate the area of the circle
5+
and display the result to the console.
6+
"""
7+
8+
pi = 3.1415926536
9+
r = 12.35
10+
11+
area = pi * (r ** 2)
12+
13+
print('The area of a circle with radius', r, 'is', area)
14+
# fmt: on
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
"""Continuing a statement across lines with parentheses, brackets, or braces.
2+
3+
Code from the "Implicit Line Continuation" section of the tutorial, in the
4+
order the tutorial presents it. Any statement with an open '(', '[', or '{'
5+
is presumed incomplete until the matching closer is found, so it can run on
6+
across as many lines as you like.
7+
8+
The blocks that only define a value are given a print() here so that
9+
running the script shows you the result.
10+
"""
11+
12+
# fmt: off
13+
person1_age = 42
14+
person2_age = 16
15+
person3_age = 71
16+
17+
# The nested list from the previous section, made readable by the open
18+
# brackets.
19+
a = [
20+
[1, 2, 3, 4, 5],
21+
[6, 7, 8, 9, 10],
22+
[11, 12, 13, 14, 15],
23+
[16, 17, 18, 19, 20],
24+
[21, 22, 23, 24, 25]
25+
]
26+
print(a)
27+
28+
# A long expression wrapped in grouping parentheses, as PEP 8 advocates.
29+
someone_is_of_working_age = (
30+
(person1_age >= 18 and person1_age <= 65)
31+
or (person2_age >= 18 and person2_age <= 65)
32+
or (person3_age >= 18 and person3_age <= 65)
33+
)
34+
print(someone_is_of_working_age)
35+
36+
# Parentheses: expression grouping
37+
x = (
38+
1 + 2
39+
+ 3 + 4
40+
+ 5 + 6
41+
)
42+
print(x)
43+
44+
# Parentheses: function call
45+
print(
46+
'foo',
47+
'bar',
48+
'baz'
49+
)
50+
51+
# Parentheses: method call
52+
print(repr('abc'.center(
53+
9,
54+
'-'
55+
)))
56+
57+
# Parentheses: tuple definition
58+
t = (
59+
'a', 'b',
60+
'c', 'd'
61+
)
62+
print(t)
63+
64+
# Curly braces: dictionary definition
65+
d = {
66+
'a': 1,
67+
'b': 2
68+
}
69+
print(d)
70+
71+
# Curly braces: set definition
72+
x1 = {
73+
'foo',
74+
'bar',
75+
'baz'
76+
}
77+
# Deliberately not printed: the display order of a set of strings varies
78+
# between runs, and the tutorial shows no output for this block either.
79+
80+
# Square brackets: list definition
81+
a = [
82+
'foo', 'bar',
83+
'baz', 'qux'
84+
]
85+
print(a)
86+
87+
# Square brackets: indexing
88+
print(repr(a[
89+
1
90+
]))
91+
92+
# Square brackets: slicing
93+
print(a[
94+
1:2
95+
])
96+
97+
# Square brackets: dictionary key reference
98+
print(d[
99+
'b'
100+
])
101+
102+
# Implicit continuation stays in effect until every parenthesis, bracket,
103+
# and brace has been closed. Indentation clarifies the nested structure.
104+
a = [
105+
[
106+
['foo', 'bar'],
107+
[1, 2, 3]
108+
],
109+
{1, 3, 5},
110+
{
111+
'a': 1,
112+
'b': 2
113+
}
114+
]
115+
print(a)
116+
# fmt: on
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Statements that grow too long to read comfortably on one line.
2+
3+
Code from the "Line Continuation" section of the tutorial: these are the
4+
"before" examples that motivate implicit and explicit line continuation.
5+
The excessive line lengths are deliberate.
6+
7+
The tutorial also shows an unterminated statement that raises a
8+
SyntaxError. That block is not reproduced here because it cannot run.
9+
"""
10+
11+
# fmt: off
12+
person1_age = 42
13+
person2_age = 16
14+
person3_age = 71
15+
16+
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)
17+
print(someone_is_of_working_age)
18+
19+
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]]
20+
print(a)
21+
# fmt: on
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Putting several statements on one line with semicolons.
2+
3+
Code from the "Multiple Statements Per Line" section of the tutorial.
4+
Python allows it, PEP 8 expressly discourages it, and Ruff flags it as
5+
E702 -- which is exactly the tutorial's point, so the warnings are
6+
suppressed rather than the examples rewritten.
7+
"""
8+
9+
# fmt: off
10+
x = 1; y = 2; z = 3 # noqa: E702
11+
print(x); print(y); print(z) # noqa: E702
12+
13+
# The same result, written the way a Python programmer normally would.
14+
x, y, z = 1, 2, 3
15+
print(x, y, z, sep='\n')
16+
# fmt: on
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Statements, the basic units of instruction in a Python program.
2+
3+
Code from the "Python Statements" section of the tutorial.
4+
5+
The formatter is switched off in this folder on purpose: this tutorial is
6+
about lexical structure, so the exact line layout, whitespace, and quoting
7+
of every example below is the lesson, not incidental style.
8+
"""
9+
10+
# fmt: off
11+
print('Hello, World!')
12+
13+
x = [1, 2, 3]
14+
print(x[1:2])
15+
16+
# At the REPL a bare expression displays its value. In a script file it does
17+
# nothing at all, so you need print() to see the result.
18+
print(repr('foobar'[2:5]))
19+
# fmt: on
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""Where whitespace matters to the interpreter, and where it matters to you.
2+
3+
Code from the "Whitespace" section of the tutorial. Whitespace is mostly
4+
optional between tokens, but leaving it out hurts readability, and it
5+
becomes mandatory when it is the only thing separating an identifier from
6+
a keyword.
7+
8+
The cramped examples below are copied from the tutorial verbatim. They are
9+
not code you should write.
10+
11+
Three error examples from the tutorial are not reproduced here because they
12+
cannot run: 'sin [...]' raises a NameError, and 'y is20' and "'qux' notin
13+
[...]" both raise a SyntaxError.
14+
"""
15+
16+
# fmt: off
17+
# No whitespace at all -- the interpreter handles all of these fine.
18+
x=3;y=12 # noqa: E702
19+
print(x+y)
20+
21+
print((x==3)and(x<y))
22+
23+
a=['foo','bar','baz']
24+
print(a)
25+
26+
d={'foo':3,'bar':4}
27+
print(d)
28+
29+
x,y,z='foo',14,21.1
30+
print((x,y,z))
31+
32+
z='foo'"bar"'baz'#Comment
33+
print(repr(z))
34+
35+
# Compare these two fragments. Most people find the second easier to read.
36+
value1=100
37+
value2=200
38+
v=(value1>=0)and(value1<value2)
39+
print(v)
40+
41+
value1 = 100
42+
value2 = 200
43+
v = (value1 >= 0) and (value1 < value2)
44+
print(v)
45+
46+
# String literals can be juxtaposed with or without whitespace. The effect
47+
# is concatenation, exactly as though you had used the + operator.
48+
s = "foo"'bar''''baz'''
49+
print(repr(s))
50+
51+
s = 'foo' "bar" '''baz'''
52+
print(repr(s))
53+
54+
# Whitespace is required here to separate the identifier s from the
55+
# keyword in, and to separate the keywords not and in.
56+
s = 'bar'
57+
58+
print(s in ['foo', 'bar', 'baz'])
59+
60+
print('qux' not in ['foo', 'bar', 'baz'])
61+
# fmt: on

0 commit comments

Comments
 (0)