PyCon APAC 2022
2022/07/20 (pre-recorded) nikkie
Many thanks to all the staff who worked so hard❤️
if
for
function
Intermediate level (equivalent of those who answered "yes")
appearance pf Python
Components of Python statements: expressions and keywords
Explanation of the statement by clauses, headers, and suites
How to read PEG
Language Reference is difficult? But exciting!
Difficulty may comes from confusion between new and old grammatical expressions, so resolve it (as first step)
Data scientist at Uzabase, Inc. (NLP, Write Python)
We're hiring!! (Engineers, Data scientists, Researchers)
High level / Low level
Short introduction about compile
High level |
Low level |
High-level programming language (e.g. Python) |
Machine language |
Humans 👩💻👨💻 read and write |
Machines 🤖 read and write |
mario.py
)name = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
mario.py
🤖$ python mario.py
Input your name: nikkie
It's not Mario.
$ python mario.py
Input your name: mario
It's me, Mario!
Humans 👩💻👨💻 read and write high-level language
Machines 🤖 read and write machine language
Machines 🤖 converts program in high-level language into machine language
Machines 🤖 read high-level languages (not only machine language)
Machines 🤖 recognize the structure of programs written in high-level languages
Source code (written in Python)
Bytecode (ref: Glossary)
internal representation in the interpreter
cached in .pyc files
if
statement programname = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
Lexical analysis
Abstract Syntax Trees
Source code is string.
Parse into tokens, the smallest unit of meaning.
2,0-2,2: NAME 'if'
2,3-2,7: NAME 'name'
2,7-2,8: DOT '.'
2,8-2,13: NAME 'lower'
2,13-2,14: LPAR '('
2,14-2,15: RPAR ')'
2,16-2,18: EQEQUAL '=='
2,19-2,26: STRING '"mario"'
2,26-2,27: COLON ':'
2,27-2,28: NEWLINE '\n'
AST
Machines handle the structure of a program as a tree.
Output an abstract syntax tree from a sequence of tokens.
If(
test=Compare(
left=Call(
func=Attribute(
value=Name(id='name', ctx=Load()),
attr='lower',
ctx=Load()),
args=[],
keywords=[]),
ops=[
Eq()],
comparators=[
Constant(value='mario')]),
body=[
Expr(
Abstract syntax |
Concrete syntax |
interpreted by the interpreter |
appearance of programming language (e.g. how to write compound statements) |
Deep dive into the current appearance of compound statements (Python 3.10.5)
Machine (parser 🤖) reads whether tokens match concrete syntax or not (Key🗝 is recursion)
Share the meaning of colons and indents
Read and taste PEG together
Meaning of colons and indents: tell parser components of statement
Read and taste PEG together
Meaning of colons and indents: tell parser components of statement
Read and taste PEG together: expressed concisely and without omissions
Statements in Python
Define statements with PEG
Read PEG together
A statement is part of a suite (a “block” of code).
Compound statements contain (groups of) other statements;
The Python Language Reference 8. Compound statements
if
statementname = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
they[*compound statements] affect or control the execution of those other statements in some way (8. Compound statements)
if
statement is a branch (execute / don't execute).
clause
header
suite
A compound statement consists of one or more ‘clauses.’ (8. Compound statements)
if
statement 1/2name = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
if
statement 2/2name = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
A clause consists of a header and a ‘suite.’ (8. Compound statements)
Each clause header begins with a uniquely identifying keyword and ends with a colon. (8. Compound statements)
Specific tokens
e.g.
if
else
for
def
name = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
A suite can be [...], or it can be one or more indented statements on subsequent lines. (8. Compound statements)
name = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
name = input("Input your name: ")
if name.lower() == "mario":
print("It's me.")
print("Mario!")
else:
print("It's not Mario.")
Only the latter form[*prior quoted] of a suite can contain nested compound statements; (8. Compound statements)
Compound statements are defined recursively!
name = input("Input your name: ")
if name.lower() == "mario":
for _ in range(3):
print("It's me, Mario!")
else:
print("It's not Mario.")
Compound statements consist of clauses (headers and suites)
Colons indicate headers!
Indents indicate suites!
A statement is either an expression or one of several constructs with a keyword, such as if, while or for.
an expression
one of several constructs with a keyword
>>> if = 1231 # Cannot use as variable
File "<stdin>", line 1
if = 1231
^
SyntaxError: invalid syntax
A piece of syntax which can be evaluated to some value.
In other words, an expression is an accumulation of expression elements [...] which all return a value.
Expressions are defined recursively too!
Literals (6. Expressions 6.2.2)
e.g. 108
is literal (int
) 👉 108
is expression
Operators (6. Expressions 6.7)
e.g. 33 - 4
is expression (literal, operator, literal)
Really accumulation of expression elements (recursive)
Calls (6. Expressions 6.3.4)
e.g. print("你好")
The function call in the following example is also a statement (written as a suite)
name = input("Input your name: ")
if name.lower() == "mario":
print("It's me, Mario!")
else:
print("It's not Mario.")
✅ Statements in Python
Define statements with PEG
Read PEG together
Actually, parser was replaced by a PEG-based one.
Grammar consists of a sequence of rules of the form (PEP 617)
Definitions of the rules in PEG are:
rule_name: expression
You can find on PEP 617 'Grammar Expressions'.
literals
whitespace
|
()
[]
OR ?
Written in single quotes
e.g. 'else'
(keyword)
e.g. e1 e2
Match e1
, then match e2
.
(If it doesn't match e1
first, it won't match e1 e2
)
else_block: 'else' ':' block
First, match literal 'else'
Next, match literal ':'
Then, match the rule block
|
e.g. e1 | e2
Match e1
or e2
Note: ordered choice (left comes first. characteristic of PEG)
|
rule_name: first_rule second_rule
is equivalent of:
rule_name:
| first_rule
| second_rule
|
before first_rule
is for formatting purposes.
()
Group (with repetition later)
e.g. 1 ( e )
: Match e
e.g. 2 ( e1 e2 )
: Match e1 e2
[]
OR ?
Match optionally
e.g. [e]
(equivalent of e?
)
May or may not match e
(optionally)
*
+
join (s.e+
)
lookahead
&
!
~
*
e.g. e*
: Match zero or more occurrences of e
(i.e. zero or more repetitions)
e.g. (e1 e2)*
: Match zero or more repetitions of group (e1 e2)
+
e.g. e+
: Match one or more occurrences of e
(i.e. one or more repetitions)
e.g. (e1 e2)+
: Match one or more repetitions of group (e1 e2)
s.e+
Match one or more occurrences of e
, separated by s
(equivalent of (e (s e)*)
)
e.g. ','.e+
one or more occurrences of
e
, separated by comma:e
/e,e
/e,e,e
/ and so on
rule: 'a' 'b'
matches tokens 'a' 'b' ...
lookahead: without consuming any tokens
'a' 'b'
(b is lookahead) matches 'a' 'b' ... and next token is b
&
Positive lookahead: Succeed if matched
e.g. &e
: e
is required to match, but not consumed by match
(Prior example is the one of positive lookahead)
!
Negative lookahead: Fail if matched
e.g. primary: atom !'.' !'(' !'['
Given a
is atom
, it matches if the expression is not a.
or a(
or a[
.
~
Commit
e.g. rule_name: '(' ~ some_rule ')' | some_alt
Match '('
, but doesn't match '(' some_rule ')'
, some_alt
is not considered
Commit will not consider others in an ordered selection.
literals
whitespace
|
()
[]
OR ?
*
+
join (s.e+
)
lookahead
&
!
~
Handle the return type of rule.
Grammar actions (Secrets of Python 3.10 Better error messages)
Check PEP 617!
Introduce how to read of each symbol in PEG (i.e. meaning).
Ready to read the definitions of compound statements of Python.
✅ Statements in Python
✅ Define statements with PEG
Read PEG together
Let's read definitions written in PEG on 10. Full Grammar specification
8. Compound statements (written in BNF) is not within the scope of this time.
Impressed with a simple view point & concise explanation without omissions
compound_stmt:
| function_def
| if_stmt
| for_stmt
| while_stmt
| match_stmt
References include other statements.
Program has been tokenized (lexical analysis)! We have a sequence of tokens.
Parser checks that the sequence of tokens matches the rules.
i.e. you won't see syntax errors if you write according to the definitions.
compound_stmt:
| function_def
| if_stmt
| for_stmt
| while_stmt
| match_stmt
if
statementThe if statement is used for conditional execution:
if
statement (without PEG)?Think about it for a minute.
else presence / absence
if ...
if ... else ...
Number of elif (0 / 1 / multiple)
if ... elif ...
if ... elif ... elif ...
if ... elif ... else ...
if ... elif ... elif ... else ...
if
statement by PEGif_stmt:
| 'if' named_expression ':' block elif_stmt
| 'if' named_expression ':' block [else_block]
elif_stmt:
| 'elif' named_expression ':' block elif_stmt
| 'elif' named_expression ':' block [else_block]
else_block:
| 'else' ':' block
block
?block:
| NEWLINE INDENT statements DEDENT
| simple_stmts
block
statements: statement+
statement: compound_stmt | simple_stmts
# In brief, simple_stmts are multiple simple_stmt
block
(equivalent of suite)# indented multiple (simple or compound) statements with newline and dedent,
# OR multiple simple statements without newline
block:
| NEWLINE INDENT statements DEDENT
| simple_stmts
if
statement 1/2if_stmt:
| 'if' named_expression ':' block elif_stmt
| 'if' named_expression ':' block [else_block]
Required: Clause with a header starting with the keyword if
and following block
View point: presence or absence of elif after the if
if
statement 2/2elif_stmt:
| 'elif' named_expression ':' block elif_stmt
| 'elif' named_expression ':' block [else_block]
View point: presence or absence of elif
after the elif
if
statement expressed in PEGif
clause is required.
View point of presence or absence of elif!
else
clause is optional ([]
).
No omissions!
named_expression
named_expression
appears in the header of if
and elif
clauses.
named_expression
# Assignment expression OR (non-assignment) expression
named_expression:
| assignment_expression
| expression !':='
assignment_expression:
| NAME ':=' ~ expression
named_expression
Assignment expression :=
was big change; It affected the syntax of the control flow.
Note: appears in while
statement (not only in if
statement)
compound_stmt:
| function_def
| if_stmt
| for_stmt
| while_stmt
| match_stmt
while
statementThe while statement is used for repeated execution as long as an expression is true:
while
statementwhile_stmt:
| 'while' named_expression ':' block [else_block]
while
statementwhile_stmt:
| 'while' named_expression ':' block [else_block]
Required: Clause with a header starting with the keyword while
and following block
Optional else_block
while
else
if the expression is false (which may be the first time it is tested) the suite of the else clause, if present, is executed and the loop terminates.
A break statement executed in the first suite terminates the loop without executing the else clause’s suite.
else_block
in loop (recommend)9 Avoid else Blocks After for and while Loops
Effective Python Second Edition (Because they are easily misunderstood)
compound_stmt:
| function_def
| if_stmt
| for_stmt
| while_stmt
| match_stmt
for
statementThe for statement is used to iterate over the elements of a sequence (such as a string, tuple or list) or other iterable object:
for
statementfor_stmt:
| 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block]
| ASYNC 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block]
for
statement (out of scope: async for
)for_stmt:
| 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block]
Required: Clause with a header starting with the keyword for
and containing in
, and following block
Optional: TYPE_COMMENT
and else_block
for
statementfor x, y in points: # type: float, float
# Here x and y are floats
...
for
else
(recommend not using)When the items are exhausted ([...]), the suite in the else clause, if present, is executed, and the loop terminates.
A break statement executed in the first suite terminates the loop without executing the else clause’s suite.
compound_stmt:
| function_def
| if_stmt
| for_stmt
| while_stmt
| match_stmt
A function definition defines a user-defined function object
def
)function_def:
| decorators function_def_raw
| function_def_raw
function_def_raw:
| 'def' NAME '(' [params] ')' ['->' expression ] ':' [func_type_comment] block
| ASYNC 'def' NAME '(' [params] ')' ['->' expression ] ':' [func_type_comment] block
func_type_comment:
| NEWLINE TYPE_COMMENT &(NEWLINE INDENT)
| TYPE_COMMENT
function_def:
| decorators function_def_raw
| function_def_raw
With one or more decorators OR without ones
async def
)function_def_raw:
| 'def' NAME '(' [params] ')' ['->' expression ] ':' [func_type_comment] block
Required: Clause with a header starting with the keyword def
and containing function NAME
and ()
, and following block
params
in ()
and type hint '->' expression
are optional
func_type_comment
is also optionaldef embezzle(self, account, funds=1000000, *fake_receipts):
# type: (str, int, *str) -> None
"""Embezzle funds from account using fake receipts."""
<code goes here>
Suggested syntax for Python 2.7 and straddling code (PEP 484)
compound_stmt:
| function_def
| if_stmt
| for_stmt
| while_stmt
| match_stmt
match
statementThe match statement is used for pattern matching.
match subject:
case <pattern_1>:
<action_1>
case <pattern_2>:
<action_2>
case <pattern_3>:
<action_3>
case _:
<action_wildcard>
match
statementdef fizzbuzz(number):
match number % 3, number % 5:
case 0, 0: return "FizzBuzz"
case 0, _: return "Fizz"
case _, 0: return "Buzz"
case _, _: return str(number)
match
statementmatch_stmt:
| "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT
subject_expr:
| star_named_expression ',' star_named_expressions?
| named_expression
case_block:
| "case" patterns guard? ':' block
guard: 'if' named_expression
match
statement 1/4match_stmt:
| "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT
Required: a header starting with the soft keyword match
One or more case_block
match
statement 2/4match_stmt:
| "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT
Required: NEWLINE and INDENT
case
block cannot be written on the match
line (But e.g. if
header and block may come on the same line)
match
statement 3/4 (case_block
)case_block:
| "case" patterns guard? ':' block
Required: a header starting with the soft keyword case
block
follows (It can be continued on the same line, separated by a semicolon, or indented on the next line)
match
statement 4/4 (guard
)case_block:
| "case" patterns guard? ':' block
guard: 'if' named_expression
Forms part of the header starting with case
.
But optional (?
).
guard
>>> flag = False
>>> match (100, 200):
... case (100, 200) if flag: # Match succeeds, but guard fails
... print("Case 2")
... case (100, y): # Match! (200 is assigned to y)
... print(f"Case 3, y: {y}")
...
Case 3, y: 200
compound_stmt:
| function_def
| if_stmt
| for_stmt
| while_stmt
| match_stmt
Tasted definitions of compound statements written in PEG
simple view point
AND expressed concisely without omissions
✅ Statements in Python
✅ Define statements with PEG
✅ Read PEG together
Focus on appearance of compound statements of Python (concrete syntax).
learn how to read PEG and tasted the syntax of compound statements.
Compound statements consist of headers and suites
Colons and indents tell parser elements of statements
Taste PEG's concise expression without ommissions
Language Reference is difficult but exciting!
Enjoy development with Python!