学习日志44 python
1 解析器是什么?
在编程领域,解析器(Parser) 是一个重要的程序或组件,主要负责将某种格式的输入(通常是文本)转换为更易于处理的结构化形式(如抽象语法树 AST),以便后续程序(如编译器、解释器)进行处理。
简单来说,解析器的核心工作是 "理解" 输入的语法规则,并验证其是否符合预设的语法规范。如果符合,就将其转换为结构化数据;如果不符合,就会抛出语法错误。
以 Python 为例理解解析器的作用:
当你编写一段 Python 代码并运行时:
- 首先,解析器会对代码文本进行语法分析,检查代码是否符合 Python 的语法规则(比如括号是否匹配、缩进是否正确、关键字使用是否规范等)。
- 如果代码语法正确,解析器会将其转换为抽象语法树(AST)—— 一种用树形结构表示代码逻辑的中间形式。
- 后续的解释器或编译器会基于 AST 执行代码(解释器直接逐行执行,编译器则可能进一步编译为机器码)。
比如对于代码 a = 1 + 2,解析器会识别出这是一个赋值语句,左侧是变量a,右侧是表达式1 + 2,并将这些结构转化为 AST 中对应的节点。
解析器的应用场景:
- 编程语言的解释器 / 编译器(如 Python 解析器、JavaScript 解析器)
- 数据格式解析(如 JSON 解析器、XML 解析器,将文本格式的 JSON/XML 转换为程序可操作的对象)
- 配置文件解析(如解析
.ini、.yaml等配置文件)
总之,解析器是 "理解" 输入格式并进行结构化转换的关键组件,是很多程序处理输入的第一步。
2 Python 类中成员解释
对于Python类中单下划线_foo、双下划线__foo与__foo__的成员,下列说法正确的是?
A _foo 不能直接用于’from module import *’
B __foo解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名
C __foo__代表python里特殊方法专用的标识
D__foo 可以直接用于’from module import *’
正确答案:ABC
在 Python 中,单下划线_foo、双下划线__foo与__foo__的成员有着不同的含义和使用规则:
-
选项 A:
_foo不能直接用于from module import *。这是正确的。单下划线开头的成员被视为 "私有" 成员,按照约定,在使用from module import *时不会导入这类成员,这是一种编程规范上的限制。 -
选项 B:
__foo解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名。这是正确的,这一机制被称为名称修饰(name mangling)。目的是避免该成员在子类中被意外覆盖,增强了类的封装性。 -
选项 C:
__foo__代表 python 里特殊方法专用的标识。这是正确的,这种命名方式用于 Python 的特殊方法(也叫魔术方法),如__init__(初始化方法)、__str__(字符串表示方法)等,这些方法有着特定的功能和调用时机。 -
选项 D:
__foo可以直接用于from module import *。这是错误的,双下划线开头的成员同样不会被from module import *直接导入,而且由于名称修饰的存在,也不建议这样使用。
所以正确答案是 ABC。理解这些命名规范,有助于写出更符合 Python 风格且封装性更好的代码。
3 抽象语法树(AST)
抽象语法树(Abstract Syntax Tree,简称 AST)是源代码语法结构的一种抽象表示,它以树形结构的形式展现代码的语法结构,每个节点都代表源代码中的一种结构。
与源代码的文本形式不同,AST 忽略了一些细节(如空格、注释、分号等格式信息),只保留代码的语法结构和语义信息。它就像代码的 "骨架",能够被程序更高效地分析和处理。
AST 的特点:
- 结构化:将线性的代码文本转换为层次化的树形结构,直观反映代码各部分的嵌套关系和逻辑结构。
- 抽象性:忽略语法细节(如括号、缩进等),只保留关键语法元素(如变量、函数、表达式、语句等)。
- 可操作性:程序可以通过遍历 AST 来分析代码结构、提取信息或进行修改。
以 Python 代码为例:
对于简单的代码 a = 1 + 2 * 3,其 AST 结构大致如下:
- 根节点:赋值语句(Assignment)
- 左侧子节点:变量
a(Name) - 右侧子节点:加法表达式(BinOp)
- 左操作数:数字
1(Constant) - 运算符:
+(Add) - 右操作数:乘法表达式(BinOp)
- 左操作数:数字
2(Constant) - 运算符:
*(Multiply) - 右操作数:数字
3(Constant)
- 左操作数:数字
- 左操作数:数字
- 左侧子节点:变量
AST 的应用场景:
- 编译器 / 解释器:编程语言的处理过程中,解析器会先将代码转换为 AST,再基于 AST 进行后续的语义分析、优化或执行(如 Python 解释器对代码的执行依赖 AST)。
- 代码分析工具:如静态代码检查工具(flake8、pylint)通过分析 AST 检测代码中的语法错误、风格问题或潜在 bug。
- 代码转换工具:如 Python 2 到 Python 3 的转换工具(2to3)通过修改 AST 实现代码自动转换。
- IDE 功能支持:代码自动补全、重构、语法高亮等功能依赖 AST 对代码结构的实时分析。
简单来说,AST 是计算机理解代码的 "中间语言",它架起了人类可读的源代码和机器可处理的指令之间的桥梁。
4 列表(list)是可变对象(mutable)
代码
def changeList(nums):
nums.append('c')
print("nums",nums)
str1 = ['a','b']
print(id(str1))
changeList(str1)
print(id(str1))
print("str1",str1)
输出
1856309341440
nums ['a', 'b', 'c']
1856309341440
str1 ['a', 'b', 'c']
在 Python 中,列表(list)是可变对象(mutable),这意味着你可以在不创建新对象的情况下修改其内容。
从你提供的代码和输出结果可以清晰地看到这一点:
- 你创建了列表
str1 = ['a','b'] - 打印了
str1的内存地址(id) - 将
str1传递给changeList函数,在函数内部向列表添加了元素 'c' - 再次打印
str1的内存地址,发现它与之前完全相同 - 最后打印
str1,发现它确实包含了新添加的元素 'c'
这证明了列表是可变的 - 我们可以修改列表的内容,而列表对象本身(及其内存地址)保持不变。当列表作为参数传递给函数时,传递的是引用(内存地址),函数内部对列表的修改会影响到原始列表。
与之相对的是字符串(str)、元组(tuple)等不可变对象,对它们进行修改会创建新的对象,而不是修改原有对象。
5 print("str1", str1)
【print("str1",str1),这是什么写法,为什么要把str1先用双引号包裹?】
在 print("str1", str1) 这种写法中:
"str1"是一个字符串字面量(用双引号包裹),它的作用是作为提示文本,用来标识后面输出的内容是什么。- 后面的
str1是变量名,代表要输出的列表对象。
这样写的目的是让输出结果更易读。比如在你的代码中,输出会是:
str1 ['a', 'b', 'c']
一眼就能看出后面的列表是变量 str1 的值。
如果直接写 print(str1),输出就是:
['a', 'b', 'c']
虽然能得到结果,但无法直观知道这个列表来自哪个变量(尤其在代码复杂、输出内容多的时候)。
双引号在这里的作用只是定义字符串,和单引号 'str1' 的效果完全一样,只是 Python 中字符串可以用单引号或双引号包裹,写法上的选择而已。
更多推荐
所有评论(0)