语法介绍 =================================== ``Python`` 是一种广泛使用的解释型、高级和通用的编程语言。 **Python** 支持多种编程范型, 包括函数式、指令式、反射式、结构化和面向对象编程。 它拥有动态类型系统和垃圾回收功能, 能够自动管理内存使用, 并且其本身拥有一个巨大而广泛的标准库。 它的语言结构以及面向对象的方法, 旨在帮助程序员为小型的和大型的项目编写逻辑清晰的代码。 由于 **libsigrokdecode** 解码器使用 ``Python`` 编写, 所以必须要求编写者具备 ``Python`` 语法知识, 这里我们就简单介绍一下解码器所需要的基本语法知识, 能让大家快速上手。 给大家推荐一个在线模拟器, 可以直接在网页上编写和运行 ``Python`` 脚本: `https://c.runoob.com/compile/9/ `_ .. note:: 如果大家想要了解更多的 ``Python`` 语法知识, 可以去搜索引擎自行学习 标识符 ------------------------ Python 中标识符的命名不是随意的, 必须遵守以下命令规则 : - 由英文 ( A~Z 和 a~z ) 、下划线 (_) 和数字组成 (0-9) , 且第一个字符不能是数字 - 不能和 Python 中的保留字相同。 - 不能包含空格、@、% 以及 $ 等特殊字符。 - 区分大小写 **合法实例, 例如 :** .. code-block:: Python alientek Alientek atk123 atk_123 **不合法实例, 例如 :** :: 123atk #不能以数字开头 print #print是保留字, 不能与保留字相同 $atk #不能有特殊字符 保留字符 ------------------------ Python 所有的保留字如下表所示 : +---------------+---------------+---------------+---------------+ | and | exec | not | assert | +---------------+---------------+---------------+---------------+ | finally | or | break | for | +---------------+---------------+---------------+---------------+ | pass | class | from | print | +---------------+---------------+---------------+---------------+ | continue | global | raise | def | +---------------+---------------+---------------+---------------+ | if | return | del | import | +---------------+---------------+---------------+---------------+ | try | elif | in | while | +---------------+---------------+---------------+---------------+ | else | is | with | except | +---------------+---------------+---------------+---------------+ | lambda | yield | | | +---------------+---------------+---------------+---------------+ 注释 --------------------------0 Python 中单行注释采用 ``#`` 开头, 实例如下 : .. code-block:: Python # 这是一个单行注释实例 Python 中多行注释采用三个单引号 ``'`` 或者三个多引号 ``"``, 实例如下 : .. code-block:: Python # 这是多引号注释实例 ''' 这是三个单引号多行注释实例 这是三个单引号多行注释实例 这是三个单引号多行注释实例 ''' """ 这是三个多引号多行注释实例 这是三个多引号多行注释实例 这是三个多引号多行注释实例 """ 变量类型 (Num/Str/List/Tuple/Dict) ----------------------------------------- Python 中使用变量与C语言有很大的区别 : - 变量可以直接赋值, 不需要提前定义 - 每个变量在使用前必须提前赋值 - 赋值前 python有五种标准的数据类型 : - 数字 (Number) - 字符串 (String) - 列表 (List) - 元组 (Tuple) - 字典 (Dict) 数字 (Number) +++++++++++++++++++++++++++++++++++++ Python 支持四种不同的数字类型 : - 整型 int - 长整型 long - 浮点型 float - 复数 complex 赋值实例 : .. code-block:: Python # 整型 a = 1 b = 0 v = -100 # 长整型 a = 0123L b = 0x12345L #浮点型 a = 1.23 b = -3.14 c = 0.0 d = 32.3e+18 # 复数 a = 3.14j b = 3e+26J 字符串 (String) +++++++++++++++++++++++++++++++++++++ **字符串 (String)** 是由 Unicode 码位构成的不可变 序列。 字符串字面值有多种不同的写法 : - 单引号: '允许包含有 "双" 引号' - 双引号: "允许嵌入 '单' 引号" - 三重引号: '''三重单引号''', """三重双引号""" 。 (三重引号允许跨越多行) 赋值实例 : .. code-block:: Python a = 'single quotes' b = "double quotes" c = '''Three single quotes''' d = """Three double quotes""" print ("a[0]: ", a[0]) # 输出 s print ("b[1:5]: ", b[1:5]) # 输出 ouble 列表 (List) +++++++++++++++++++++++++++++++++++++ **列表 (List)** 是 Python 中最基本的数据类型之一, 列表中的每个元素均会分配一个数字, 用以记录位置, 我们称之为索引 (Indexes), 索引值从 0 开始, 依次往后计数。 列表使用中括号 ``[ ]`` 包裹, 元素之间使用逗号 ``,`` 分隔, 其元素可以是数字、字符串、列表等其他任何数据类型。 列表支持索引、更新、删除、嵌套、拼接、成员检查、截取、追加、扩展、排序等相关操作, 具体操作可以使用搜索引擎进行查阅。 列表使用实例 : .. code-block:: Python def_list = [] # 空列表 def_list = list() # 使用 list() 方法定义一个空列表 list = [ 'atk', 123 , 3.45, 'ALIENTEK', 70.2 ] print (list) # 输出完整列表 print (list[0]) # 输出列表第一个元素 print (list[1:3]) # 从第二个开始输出到第三个元素 # 列表嵌套列表 a = [[1,2,3],[4,5,6],[7],[8,9]] print(a[1][0]) # 输出 4 # 列表嵌套字典 b = [{'a': 1}, {'b': 2}, {'c': 3}] print(b[1]['b']) # 输出 2 元组 (Tuple) +++++++++++++++++++++++++++++++++++ **元组 (Tuple)** 是 Python 中基本数据结构之一, 与列表类似, 但元组中的元素不允许被修改, 因此元组也被称作 **只读列表** 。 元组使用小括号 ``( )`` 包裹, 元素之间使用逗号 ``,`` 分隔, 元组中的元素可以是字符串、数字、列表、元组等其他数据类型。 元组不支持修改, 但支持索引、拼接、成员检查、重复等相关操作。 .. code-block:: Python def_tuple = () # 空元组 def_tuple = tuple() # 使用 tuple() 方法定义一个空元组 tuple = ( 'atk', 123 , 3.45, 'ALIENTEK', 70.2 ) print (tuple) # 输出完整元组 print (tuple[0]) # 输出元组的第一个元素 print (tuple[1:3]) # 输出从第二个元素开始到第三个元素 字典 (Dict) +++++++++++++++++++++++++++++++++++++ 字典 (Dictionary) 是 Python 中常用的数据结构之一, 它用于存放具有映射关系的数据, 其灵活性极高, 可存储任意类型的数据对象, 它有时也被称作关联数组或哈希表。 字典以键值对的形式存储数据, 每个键值对以冒号 ``:`` 连接, 冒号左侧为键 (key) , 右侧为值 (value) , 且键与值都使用单引号 ``' '`` 或 双引号 ``" "`` 包裹。 字典使用大括号 ``{ }`` 包裹, 键值对之间使用逗号 ``,`` 分隔, 与列表不同, 字典中的元素是无序的。 字典支持更新、删除、嵌套、拼接、成员检查、追加、扩展、排序等相关操作。 .. code-block:: Python def_dict = {} # 空字典 def_dict = dict() # 使用 dict() 方法定义一个空字典 dict = {'name' : 'alientek', 'code' : 1, 'value' : 1.23, 2 : 'ALIENTEK'} dict['name'] = "alientek" dict['code'] = 1 dict[2] = 'ALIENTEK' print (dict['name']) # 输出键为 'name' 的值 print (dict[2]) # 输出键为 2 的值 # 字典嵌套字典 a = { '192.168.1.1':{'cpu':'0.23','内存':'16','硬盘':'500'}, '192.168.1.2':{'cpu':'3.22','内存':'64','硬盘':'700'}, '192.168.1.3':{'cpu':'1.99','内存':'32','硬盘':'800'}, } print (a['192.168.1.2']['cpu']) # 输出 3.22 # 字典嵌套列表 a = { '水果':['苹果','香蕉','橘子'], '动物':['狮子','老虎','大象'], '语言':['中文','英文','日语'], } print (a['语言'][0]) # 输出 中文 函数 ------------------------ 函数是组织好的, 可重复使用的, 用来实现单一, 或相关联功能的代码段。 函数能提高应用的模块性, 和代码的重复利用率。Python提供了许多内建函数, 比如print(),当然我们自己也可以创建函数。 在 Python 中, 使用 ``def`` 关键字定义函数 : .. code-block:: Python # 函数定义 def my_function(): print("Hello from a function") #函数调用 my_function() 带参数的函数定义和调用实例: .. code-block:: Python # 函数定义 def my_function(info): print("Hello from a function : " + info) #函数调用 my_function('alientek') while 循环 ------------------------ **while** 循环语句的控制结构图如下所示 : .. image:: /img/while.svg :alt: 无法显示图片 :align: center Python 中 ``while`` 语句的格式如下 : .. code-block:: Python while <条件表达式>: [语句块] 解释 : 当 **while** 的 ``<条件表达式>`` 为 ``True`` 时运行 ``[语句块]`` , ``[语句块]`` 运行结束后, 再次进入 ``<条件表达式>`` 进行判断。 如果 ``<条件表达式>`` 结果为 ``True`` 则再次运行【语句块】, 以此循环直到 ``<条件表达式>`` 结果为 ``False`` 结束循环。 for 循环 ------------------------ Python 中的 for 循环是迭代循环, 可以遍历任何的序列对象或可迭代对象, 如 str、list、tuple 、 dict 等。 遍历时, for 循环语句将遍历对象中的所有成员, 遍历顺序与成员在对象中的顺序一致, 它会对每个成员执行一次循环体, 循环的次数在程序开始运行时就已经指定。 for 循环语句由 for 与 in 搭配组成, 它依次迭代出对象中的每个元素, 并将元素的值传递给临时变量, 然后执行一次循环体。 ``for`` 语句格式如下 : .. code-block:: Python for <循环变量> in <序列> [循环代码块] **for** 循环语句的控制结构图如下所示 : .. image:: /img/for.svg :alt: 无法显示图片 :align: center 如, 我现在要遍历循环一个字符串, 把每个字符单独输出 : .. code-block:: Python string = '123456' for i in string: print(i) # 输出结果 1 2 3 4 5 6 以上结果, 等于把整个字符串逐个的拆开循环遍历打印出来。 if else 条件判断 ------------------------ Python 条件控制是通过一条或多条语句的条件是 ``True`` 还是 ``False`` 来决定执行的代码块。 if 如果条件为 ``真`` 则执行 ``语句块1`` , 为 ``假`` 执行 ``语句块2`` , 如下图所示 : .. image:: /img/ifelse.svg :alt: 无法显示图片 :align: center if 语句格式如下 : .. code-block:: Python if <条件1>: [条件1 代码块] elif <条件2>: [条件2 代码块] else: [else 代码块] 三元表达式 ------------------------ 我们从一个具体的例子切入本节内容。假设现在有两个数字, 我们希望获得其中较大的一个, 那么可以使用 if else 语句, 例如 : .. code-block:: Python if a>b: max = a; else: max = b; Python 提供了一种更加简洁的写法, 如下所示 : .. code-block:: Python max = a if a>b else b 这是一种类似于其它编程语言中三目运算符 ``? :`` 的写法。Python 是一种极简主义的编程语言, 它没有引入? :这个新的运算符, 而是使用已有的 if else 关键字来实现相同的功能。 Python 使用 if else 实现三目运算符 (条件运算符) 的格式如下 : .. code-block:: Python exp1 if condition else exp2 解释 : ``condition`` 是判断条件, ``exp1`` 和 ``exp2`` 是两个表达式。如果 ``condition`` 成立 (结果为真) , 就执行 ``exp1``, 并把 ``exp1`` 的结果作为整个表达式的结果; 如果 ``condition`` 不成立 (结果为假), 就执行 ``exp2``, 并把 ``exp2`` 的结果作为整个表达式的结果。 前面的语句 ``max = a if a>b else b`` 的含义是 : - 如果 a>b 成立, 就把 a 作为整个表达式的值, 并赋给变量 max - 如果 a>b 不成立, 就把 b 作为整个表达式的值, 并赋给变量 max 类(class)和实例(Instance) ---------------------------------- 本章节我们将简单介绍一下 Python 的面向对象编程。 如果以前没有接触过面向对象的编程语言, 那你可能需要先了解一些面向对象语言的一些基本特征, 在头脑里头形成一个基本的面向对象的概念, 这样有助于你更容易的学习Python的面向对象编程。请大家自行查阅其他相关资料。 面向对象编程 —— Object Oriented Programming, 简称 ``OOP`` , 是一种程序设计思想。 ``OOP`` 把对象作为程序的基本单元, 一个对象包含了数据和操作数据的函数。 面向对象最重要的概念就是 ``类 (Class)`` 和 ``实例 (Instance)`` , 在 Python 中, 类是通过 ``class`` 关键字定义的 : .. code-block:: Python class Student(object): pass 解释 : ``class`` 后面紧接着是类名, 即 Student , 类名通常是大写开头的单词, 紧接着是 (object) , 表示该类是从哪个类继承下来的, 继承的概念我们这里不讲, 请大家自行查阅相关资料。 通常, 如果没有合适的继承类, 就使用 object 类, 这是所有类最终都会继承的类。而在协议解码库中必须是基于 ``srd.Decoder`` 创建类。 定义好了 Student 类, 就可以根据 Student 类创建出 Student 的实例, 创建实例是通过 ``类名+()`` 实现的 : .. code-block:: Python zhangsan = Student() 解释 : 变量 zhangsan 指向的就是一个 Student 的实例 我们可以自由地给一个实例变量绑定属性, 比如给实例 zhangsan 绑定一个 name 属性。 由于类可以起到模板的作用, 因此, 可以在创建实例的时候, 把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的 ``__init__`` 方法, 在创建实例的时候, 就把 name, score 等属性绑上去 : .. code-block:: Python class Student(object): def __init__(self, name, score): self.name = name self.score = score 注意: - 特殊方法 ``__init__`` 前后分别有两个下划线!!! - ``__init__`` 方法的第一个参数永远是 ``self`` , 表示创建的实例本身, 因此, 在 ``__init__`` 方法内部, 就可以把各种属性绑定到 ``self`` , 因为 ``self`` 就指向创建的实例本身 有了__init__方法, 在创建实例的时候, 就不能传入空的参数了, 必须传入与__init__方法匹配的参数, 但self不需要传, Python解释器自己会把实例变量传进去 : .. code-block:: Python # 创建实例 zhangsan = Student('zhangsan_name', 80) print(zhangsan.name) # 输出 zhangsan_name print(zhangsan.score) # 输出 80 和普通的函数相比, 在类中定义的函数只有一点不同, 就是第一个参数永远是实例变量 ``self`` , 并且在调用时不用传递该参数。 除此之外, 类的方法和普通函数没有什么区别, 所以仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。 面向对象编程的一个重要特点就是数据封装。在上面的 Student 类中, 每个实例就拥有各自的 name 和 score 这些数据。我们可以通过函数来访问这些数据, 比如打印一个学生的成绩 : .. code-block:: Python # 实例化一个类 zhangsan = Student('zhangsan_name', 80) def print_info(std): print('%s: %d' % (std.name, std.score)) print_info(zhangsan) # 输出 zhangsan_name: 80 既然 Student 实例本身就拥有这些数据, 要访问这些数据, 就没有必要从外面的函数去访问, 可以直接在 Student 类的内部定义访问数据的函数。 这样就把 ``数据`` 给封装起来了。而这些封装数据的函数是和 Student 类本身是关联起来的, 我们称之为类的方法 : .. code-block:: Python class Student(object): def __init__(self, name, score): self.name = name self.score = score def print_info(self): print('%s: %d' % (std.name, std.score)) 要定义一个方法, 除了第一个参数是 self 外, 其他和普通函数一样。要调用一个方法只需要在实例变量上直接调用, 除了 self 不用传递, 其他参数正常传入 : .. code-block:: Python # 实例化一个类 zhangsan = Student('zhangsan_name', 80) zhangsan.print_info() # 输出 zhangsan_name: 80 这样从外部看 Student 类, 就只需要知道创建实例需要给出 name 和 score , 而如何打印都是在 Student 类的内部定义的, 这些数据和逻辑被 ``封装`` 起来了, 调用很容易, 却不用知道内部实现的细节。 封装的另一个好处是可以给 Student 类增加新的方法, 比如get_grade, 该方法可以直接在实例变量上调用, 不需要知道内部实现细节 : .. code-block:: Python class Student(object): def __init__(self, name, score): self.name = name self.score = score def get_grade(self): if self.score >= 90: return 'A' elif self.score >= 60: return 'B' else: return 'C' zhangsan = Student('zhangsan', 99) xiaoming = Student('xiaoming', 59) print(zhangsan.name, zhangsan.get_grade()) # 输出 zhangsan A print(xiaoming.name, xiaoming.get_grade()) # 输出 xiaoming C 总结 : - 类是创建实例的模板, 而实例则是一个一个具体的对象, 各个实例拥有的数据都互相独立, 互不影响 - 方法就是与实例绑定的函数, 和普通函数不同, 方法可以直接访问实例的数据 - 通过在实例上调用方法, 就直接操作对象内部的数据, 但无需知道方法内部的实现细节 - 和静态语言不同, Python 允许对实例变量绑定任何数据, 也就是说, 对于两个实例变量, 虽然它们都是同一个类的不同实例, 但拥有的变量名称都可能不同