关于Python词法分析:Python词汇分析 – 逻辑和&

Python lexical analysis - logical line & compound statements

所以我明白:

The end of a logical line is represented by the token NEWLINE

这意味着定义python语法的方式结束逻辑行的唯一方法是使用
标记。

物理行(而不是eol,它是您在编写文件时使用的平台的eol,但仍然通过python转换为通用的

逻辑行可以或不能等同于一个或多个物理行,但通常它是一个,而且大多数情况下,如果编写干净的代码,它就是一个。

在这个意义上:

1
2
3
4
5
6
7
8
9
foo = 'some_value'  # 1 logical line = 1 physical  
foo, bar, baz = 'their', 'corresponding', 'values'  # 1 logical line = 1 physical
some_var, another_var = 10, 10; print(some_var, another_var); some_fn_call()

# the above is still still 1 logical line = 1 physical line
# because ; is not a terminator per se but a delimiter
# since Python doesn't use EBNF exactly but rather a modified form of BNF

# p.s one should never write code as the last line, it's just for educational purposes

不显示1逻辑如何等价于1物理的示例,我的问题是来自文档的以下部分:

Statements cannot cross logical line boundaries except where NEWLINE
is allowed by the syntax (e.g., between statements in compound
statements)

但这甚至意味着什么?我理解复合语句的列表,即它们:if、while、for等。它们都由一个或多个子句组成,而每个子句又由一个标题和一个套件组成。该套件由一个或多个语句组成,让我们以一个更具体的示例为例:

所以根据语法,if语句是这样的(不包括elifs和else子句):

1
if_stmt ::= "if" expression":" suite

如果套房及其后续声明:

1
2
3
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

这意味着,如果你想,你可以选择(由""给出)你的套房是两种方式之一:

  • 在同一行:

    缺点:不是pythonic,并且不能有其他引入新块的复合语句(如func def、其他if等)

    宣传:我想是一行

  • 例子:

    1
    if 'truthy_string': foo, bar, baz = 1, 2, 3; print('whatever'); call_some_fn();
  • 引入新块:

    优点:所有,以及正确的方法

  • 例子:

    1
    2
    3
    4
    5
    6
    if 'truthy_value':
        first_stmt = 5
        second_stmt = 10
        a, b, c = 1, 2, 3
        func_call()
        result = inception(nested(calls(one_param), another_param), yet_another))

    但我不明白

    Statements cannot cross logical line boundaries except where NEWLINE
    is allowed by the syntax

    我在上面看到的是一个套件,它是由if子句控制的代码块,反过来,这个套件由逻辑独立的行(语句)组成,其中每个逻辑行都是一个物理行(巧合)。我不明白一条逻辑线是如何跨越界限的(基本上只是一个结尾的花哨词,界限,即换行符),我不明白一条语句是如何跨越这些界限,跨入下一条语句,或者我真的很困惑,把所有的事情都搞混了,但是如果有人能解释的话。

    感谢您提前抽出时间。


    Python语法

    幸运的是,Python文档中有完整的语法规范。

    该规范中的语句定义为:

    1
    stmt: simple_stmt | compound_stmt

    逻辑行由NEWLINE分隔(这不在规范中,而是基于您的问题)。

    一步一步

    好吧,我们来看看这个,A的规格是什么

    simple_stmt

    1
    2
    3
    simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
    small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
                 import_stmt | global_stmt | nonlocal_stmt | assert_stmt)

    好吧,现在它进入了几个不同的路径,并且可能没有意义单独地通过所有路径,但是根据规范,如果任何一个small_stmt中包含NEWLINEsimple_stmt可以跨越逻辑线边界(目前它们不但是可以)。

    除此之外,只有理论上的可能性

    compound_stmt

    1
    2
    3
    4
    5
    compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt
    [...]
    if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
    [...]
    suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

    我只选择了ifsuite,因为它已经足够了。包括elifelse在内的if报表,所有内容均为一个报表(复合报表)。因为它可能包含NEWLINEs(如果suite不仅仅是simple_stmt的话),它已经满足了"跨越逻辑线边界的语句"的要求。

    示例if(示意图):

    1
    2
    3
    if 1:
        100
        200

    将是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if_stmt
    |---> test        --> 1
    |---> NEWLINE
    |---> INDENT
    |---> expr_stmt   --> 100
    |---> NEWLINE
    |---> expr_stmt   --> 200
    |---> NEWLINE
    |---> DEDENT

    所有这些都属于if语句(它不仅仅是由ifwhile控制的块)。

    parsersymboltoken相同的if

    一种可视化的方法是使用内置的parsertokensymbol模块(实际上,我在写答案之前还不知道这个模块):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import symbol
    import parser
    import token

    s ="""
    if 1:
        100
        200
    """

    st = parser.suite(s)

    def recursive_print(inp, level=0):
        for idx, item in enumerate(inp):
            if isinstance(item, int):
                print('.'*level, symbol.sym_name.get(item, token.tok_name.get(item, item)), sep="")
            elif isinstance(item, list):
                recursive_print(item, level+1)
            else:
                print('.'*level, repr(item), sep="")

    recursive_print(st.tolist())

    实际上,我不能解释大多数parser结果,但它表明(如果你删除了许多不必要的行)suite包括它的新行实际上属于if_stmt。缩进表示解析器在特定点的"深度"。

    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
    26
    27
    file_input
    .stmt
    ..compound_stmt
    ...if_stmt
    ....NAME
    ....'if'
    ....test
    .........expr
    ...................NUMBER
    ...................'1'
    ....COLON
    ....suite
    .....NEWLINE
    .....INDENT
    .....stmt
    ...............expr
    .........................NUMBER
    .........................'100'
    .......NEWLINE
    .....stmt
    ...............expr
    .........................NUMBER
    .........................'200'
    .......NEWLINE
    .....DEDENT
    .NEWLINE
    .ENDMARKER

    这可能会变得更漂亮,但我希望它可以作为说明,即使在它的当前形式。


    比你想象的简单。复合语句被视为单个语句,即使其中可能包含其他语句。引用文档:

    Compound statements contain (groups of) other statements; they affect or control the execution of those other statements in some way. In general, compound statements span multiple lines, although in simple incarnations a whole compound statement may be contained in one line.

    例如,

    1
    2
    3
    if a < b:
        do_thing()
        do_other_thing()

    是一个单if语句,占用3个逻辑行。这就是语句如何跨越逻辑线边界。