Python深度学习:逻辑、算法与编程实战
上QQ阅读APP看书,第一时间看更新

1.3 Python基本语法

Python语言与Perl、C和Java等语言有许多相似之处,但也存在一些差异。下面介绍Python的基础语法,帮助读者快速学会Python编程。

1.3.1 保留字和标识符

标识符是用于识别类、变量、函数、序列、元组、字典、函数以及其他对象的名字,标识符可以包含字母、数字及下划线。Python保留字(又称关键字)是Python语言中已经被赋予特定意义的单词集合。开发程序时,不能把这些保留字作为变量、函数、类、模块和其他对象的标识符来使用。

在Python IDE中输入“import keyword keyword.kwlist”,列出所有的Python保留字,图1-27为Python的保留字。

图1-27 Python的保留字

Python保留字的说明如表1-1所示。

表1-1 Python保留字的说明

(续)

1.3.2 变量和数据类型

Python处理的数据类型非常丰富,下面分别进行说明。

1.Python变量

Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,没有类型,我们所说的“类型”是变量所指的内存中对象的类型。

赋值号(=)用来给变量赋值。赋值号(=)运算符左边是一个变量名,赋值号(=)运算符右边是存储在变量中的值。在Python Shell中的变量实例如下。

Python允许同时为多个变量赋值。

例如:a = b = c = 1。创建一个整型对象,值均为1,三个变量被分配到相同的内存空间上。

在Python中,也可以为多个对象指定多个变量。

例如:a, b, c = 1, 2, "hellow"。将两个整型对象1和2分配给变量a和b,字符串对象"hellow" 分配给变量c。

可以使用del语句删除一些对象引用,del语句的语法如下。

2.Python数据类型

Python中有如下几个标准的数据类型。

需要注意的是,在Python2中是没有布尔型数据的,而是用数字0表示False,用1表示True。在Python3中,True和False被定义成了关键字,但它们的值还是1和0,可以和数字相加。

1)Number(数字)

Python3支持int、float、bool、complex(复数)数据类型,例如:

在Python Shell中的数字实例如下。

另外,Python还支持复数,复数由实数部分和虚数部分构成,可以用a+bj或者complex(a,b)表示,复数的实数部分a和虚数部分b都是浮点型,例如:

2)String(字符串)

Python中的字符串用单引号或双引号引起来,同时使用反斜杠(\)转义特殊字符。

字符串截取的语法格式:变量[头下标:尾下标]。

索引值以0为开始值,-1为从末尾的开始位置。

加号(+)是字符串的连接符,星号(*)表示复制当前字符串,紧跟的数字为复制的次数。在Python Shell中的字符串实例如下。

需要注意的是,Python没有单独的字符类型,一个字符就是长度为1的字符串。

3)List(列表)

List(列表)是Python中使用最频繁的数据类型。

列表可以完成大多数集合类的数据结构实现。列表中元素的类型可以不相同,它支持数字、字符串,甚至可以包含列表(嵌套)。列表是写在方括号之间,用逗号分隔开的元素列表。和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表。

列表截取的语法格式:变量[头下标:尾下标]。索引值以0为开始值,-1为从末尾的开始位置。加号(+)是列表连接运算符,星号(*)表示重复操作。在Python Shell中的列表实例如下。

与Python字符串不一样的是,列表中的元素是可以改变的,List内置了很多方法,例如append()、pop()等。需要注意如下几点。

(1)List写在方括号之间,元素用逗号隔开。

(2)和字符串一样,List可以被索引和切片。

(3)List可以使用+操作符进行拼接。

(4)List中的元素是可以改变的。

4)Tuple(元组)

元组与列表类似,不同之处在于元组的元素不能修改。元组写在小括号里,元素之间用逗号隔开,元组中的元素类型也可以不相同。在Python Shell中的元组实例如下。

元组与字符串类似,可以被索引且下标索引从0开始,-1为从末尾开始的位置。元组也可以截取,其实,可以把字符串看作一种特殊的元组。虽然Tuple的元素不可改变,但它可以包含可变的对象。String、List和Tuple都属于Sequence(序列)。

注意如下几点。

(1)与字符串一样,元组的元素不能修改。

(2)元组也可以被索引和切片。

(3)注意构造包含0或1个元素的元组的特殊语法规则。

(4)元组也可以使用+操作符进行拼接。

5)Set(集合)

集合(Set)是一个无序不重复元素的序列。基本功能是进行成员关系测试和删除重复元素。

可以使用大括号{ }或者Set()函数创建集合,创建一个空集合必须用Set()而不是{ },因为{}专门用来创建空字典。

创建格式:parame={value01,value02,...} 或者set(value)。

在Python Shell中的集合实例如下。

6)Dictionary(字典)

字典(Dictionary)是Python中另一个非常有用的内置数据类型。

列表是有序的对象结合,字典是无序的对象集合。两者之间的区别在于字典中的元素是通过键来存取的,而不是通过偏移存取。

字典是一种映射类型,用{}标识,它是一个无序的键(Key):值(Value)对集合。

键(Key)必须使用不可变类型。在同一个字典中,键(Key)必须是唯一的。

在Python Shell中的字典实例如下。

构造函数dict()可以直接从键值对序列中构建字典,示例如下。

另外,字典类型也有一些内置的函数,例如clear()、keys()、values()等。

注意以下几点。

(1)字典是一种映射类型,它的元素是键值对。

(2)字典的关键字必须为不可变类型,且不能重复。

(3)创建空字典使用{}。

3.Python数据类型转换

有时候需要对数据内置的类型进行转换。转换数据类型时,只需要将数据类型作为函数名即可。

表1-2为几个典型的可以执行数据类型之间转换的内置函数,这些函数返回一个新的对象,表示转换的值。

表1-2 数据类型转换

1.3.3 基本控制结构

Python基本控制结构包括顺序结构、选择结构和循环结构。

1.if语句

Python条件语句通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。

Python中if语句的一般形式如下。

如果condition_1为True,将执行statement_block_1块语句;如果condition_1为False,将判断condition_2,如果condition_2为True,将执行statement_block_2块语句;如果condition_2为False,将执行statement_block_3块语句。

注意以下几点。

(1)Python中用elif代替了else if,所以if语句的关键字为:if-elif-else。

(2)每个条件后面要使用冒号(:),表示接下来是满足条件后要执行的语句块。

(3)使用缩进来划分语句块,相同缩进数的语句在一起组成一个语句块。

(4)在Python中没有switch-case语句。

下面展示一个简单的if实例。

if中常用的操作运算符有:<(小于)、<=(小于或等于)、>(大于)、>=(大于或等于)、==(等于,比较对象是否相等)和!=(不等于)。

2.if嵌套

在嵌套if语句中,可以把if-elif-else结构放在另外一个if-elif-else结构中,一般形式如下。

例如,在Python编辑器中输入以下代码,保存到“embedded_if.py”文件中。

执行后输出结果如下。

3.循环语句while

Python中while语句的一般形式如下。

同样需要注意冒号和缩进。另外,在Python中没有do-while循环。

以下实例使用了while来计算1到100的总和。

执行结果为“1到100之和为:5050”。

4.while循环使用else语句

在while-else语句中,当条件语句为false时,执行else的语句块。

简单实例如下。

执行以上脚本,输出结果如下。

5.循环语句for语句

Python的for循环可以遍历任何序列的项目,如一个列表或者一个字符串。

for循环的一般格式如下。

在Python Shell中的for循环实例如下。

for实例可使用break语句,break语句用于跳出当前循环体。

6.range()函数

如果需要遍历数字序列,可以使用内置range()函数,它会生成数列,实例如下。

也可以设置间隔,实例如下。

7.break和continue语句及循环中的else子句

break语句可以跳出for和while的循环体。如果从for或while循环中终止,任何对应的循环else块将不执行。continue语句用于告诉Python跳过当前循环块中的剩余语句,然后继续进行下一轮循环。

8.pass语句

pass是空语句,是为了保持程序结构的完整性。pass不起任何作用,一般用作占位语句,实例如下。

9.使用内置enumerate()函数进行遍历

该函数使用格式如下。

在Python Shell中的实例如下。

输出结果如下。

10.循环嵌套

使用while循环嵌套来实现99乘法法则的代码如下。

for循环嵌套的使用实例如下。

输出结果如下。

1.3.4 运算符

Python语言和C语言、Java、PHP等一样,都离不开运算操作,运算操作要用到运算符。Python运算符可以分为算术运算符、比较运算符、逻辑运算符、赋值运算符、成员运算符、身份运算符以及位运算符等,如表1-3所示。

表1-3 Python的运算符

(续)

1.3.5 函数

函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码段。函数能提高应用的模块性和代码的重复利用率。Python提供了许多内置函数,比如print()。当然,也可以创建自己的函数,即用户自定义函数。

1.定义一个函数

可以定义一个具有自己想要功能的函数,以下是简单的规则。

(1)函数代码块以def关键词开头,后接函数标识符名称和圆括号()。

(2)任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

(3)函数的第一行语句可以选择性地使用文档字符串(-)用于存放函数说明。

(4)函数内容以冒号起始,并且缩进。

(5)使用return表达式结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None。

函数定义语法格式如下。

默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。

函数应用实例如下。

以上实例输出结果如下。

2.函数调用

定义一个函数以后,可以通过另一个函数调用执行,也可以直接从Python命令提示符中执行。

如下实例中调用了printstr()函数。

以上实例输出结果如下。

3.参数传递

在Python中,类型属于对象,变量是没有类型的,例如:

以上代码中,[1,2,3]是List类型,"Hellow"是String类型,而变量a是没有类型,仅仅是一个对象的引用(一个指针),可以是List类型对象,也可以指向String类型对象。

4.可更改与不可更改对象

在Python中,Strings、Tuples以及Numbers是不可更改的对象,而List、Dict等则是可以更改的对象。

(1)不可变类型:变量赋值a=8后再赋值a=10,这里实际是新生成一个int值对象10,再让a指向它,而8被丢弃,不是改变a的值,相当于新生成了a。

(2)可变类型:变量赋值pa=[1,2,3,4]后,再赋值pa[2]=5,则是将List pa的第三个元素值更改,本身pa没有动,只是其内部的一部分值被修改了。

Python函数的参数传递如下。

(1)不可变类型:类似于C++的值传递,如整数、字符串、元组。例如,fun(x)传递的只是x的值,没有影响x对象本身。若在fun(x)内部修改x的值,则只是修改另一个复制的对象,不会影响x本身。

(2)可变类型:类似于C++的引用传递,如列表、字典。例如,Fun(pa)是将pa真正地传过去,修改后fun外部的pa也会受影响。

Python中一切都是对象,严格来说,不应该说成值传递或是引用传递,应该说传不可变对象和传可变对象。

Python传不可变对象实例如下。

实例中有整型对象2,指向它的变量是b,在传递给ChangeInt()函数时,按传值的方式复制的变量b,x和b都指向了同一个Int对象,在x=10时,则新生成一个Int值对象10,并让x指向它。

可变对象在函数里修改了参数,那么在调用这个函数时,函数的原始参数也被改变了,例如:

传入函数的对象和在末尾添加新内容的对象用的是同一个引用,因此输出结果如下。

5.参数

调用函数时可使用的正式参数类型如下。

1)必需参数

必需参数要以正确的顺序传入函数,调用时的参数数量必须和声明时的参数数量一样。

调用printstr()函数,必须传入一个参数,不然会出现语法错误,例如:

以上实例输出结果如下。

2)关键字参数

关键字参数允许传入0个或任意一个含参数名的参数,这些关键字参数在函数内部自动组成为一个Dict,例如:

输出结果如下。

3)默认参数

调用函数时,如果没有传递参数,则会使用默认参数。以下实例中,如果没有传入age参数,则使用默认值。

以上实例输出结果如下。

4)不定长参数

如果需要一个函数能处理比当初声明时更多的参数,这些参数叫作不定长参数,和上述几种参数不同,参数声明时不会命名,基本语法如下。

加了星号(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组,也可以不向函数传递未命名的变量。不定长参数实例如下。

以上实例输出结果如下。

6.匿名函数

Python使用lambda来创建匿名函数。所谓匿名,意即不再使用def语句这样标准的形式定义一个函数。lambda只是一个表达式,函数体比def函数简单很多。

lambda的主体是一个表达式,而不是一个代码块,只能在lambda表达式中封装有限的逻辑。lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。

虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而提高运行效率。

lambda函数的语法只包含一个语句:

实例如下。

以上实例输出结果如下。

7.return语句

return语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。之前的实例中都没有示范如何返回数值,以下实例演示了return语句的用法。

以上实例输出结果如下。

8.变量作用域

在Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种,分别如下。

(1)L(Local):局部作用域。

(2)E(Enclosing):闭包函数外的函数中。

(3)G(Global):全局作用域。

(4)B(Built-in):内建作用域。

在Python中,以L>E>G>B规则查找变量,即在局部找不到时,便会去局部外的局部查找(例如闭包),若依然找不到,则会去全局查找,再去内建中查找。

Python中只有模块(module)、类(class)以及函数(def、lambda)会引入新的作用域,其他的代码块(如if-elif-else、try-except、for-while等)是不会引入新的作用域的,也就是说外部也可以访问这些语句内定义的变量,示例如下。

实例中msg变量定义在if语句块中,但外部还是可以访问的。

如果将msg定义在函数中,则它就是局部变量,外部不能访问。

从报错的信息上看,说明了msg_inner未定义无法使用,因为它是局部变量,只有在函数内可以使用。

9.全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的变量拥有全局作用域。局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中,实例如下。

以上实例输出结果如下。

10.global和nonlocal关键字

当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字。在以下实例中将修改全局变量num。

以上实例输出结果如下。

如果要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量,则需要使用nonlocal关键字,实例如下。

以上实例输出结果如下。

另外,要注意一种特殊情况,假设下面这段代码被运行。

执行以上程序,报错信息如下。

错误信息为局部作用域引用错误,因为test()函数中的a使用的是局部未定义的变量,无法修改。

1.3.6 with语句

Python中有很多任务需要事先设置和事后清理,在这种情况下,使用with语句处理会非常方便。一个典型的例子就是文件处理,读取文件的一般代码如下。

用户有时可能会忘记关闭文件,或者在读取数据时发生异常,没有进行任何处理,这时使用with可以很好地处理这些问题,使用with语句的代码如下。

with的使用格式如下。

with后面为一个表达式,表达式被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量,方便之后操作。然后执行with block代码块,不论成功、错误或异常,在with block执行结束后,会调用前面返回对象的__exit__()方法。

1.3.7 字符串操作

字符串是Python中最常用的数据类型,可以使用单引号或双引号来表示字符串。创建字符串很简单,只要为变量分配一个值即可,例如:

1.访问字符串中的值

Python不支持字符类型,在Python中单字符也作为一个字符串使用。在Python中,可以使用方括号来截取字符串,例如:

2.字符串运算符

假设变量s1值为"Hello",变量s2的值为"Python",则字符串运算如下。

s1+s2的值为'HelloPython'。

s1*2的值为'HelloHello'。

"H"in s1的值为True。

"M"not in s1的值为True。

r'\n' 的值为\n,r接的字符串为原始字符串,所有的字符串都是直接按照字面的意思来使用。

3.字符串内置函数

Python字符串的操作大部分是通过Python的字符串内置函数实现的,字符串的内置函数列表如图1-28所示。

图1-28 Python的字符串内置函数

Python的字符串常用内置函数说明如表1-4所示。

表1-4 Python的字符串常用内置函数

1.3.8 异常处理

异常即是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行。一般情况下,在Python无法正常处理程序时,就会发生一个异常。异常是Python对象,表示一个错误。当Python脚本发生异常时,我们需要捕获处理它,否则程序会终止执行。

捕捉异常可以使用try-except语句。try-except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。如果不想在异常发生时结束程序,则要在try里捕获它。

以下为简单的try-except-else的语法。

Try的工作原理是,当开始一个try语句后,Python就在当前程序的上下文中做标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。

如果try后的语句执行时发生异常,Python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)。

如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印默认的出错信息)。

如果在try子句执行时没有发生异常,Python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。

下面是简单的实例,将打开一个文件,在该文件中写入内容,且并未发生异常。

以上程序输出结果如下。

下面的实例中,将打开一个文件,在该文件中写入内容,但该文件没有写入权限,因此发生了异常。

在执行代码前为了测试方便,可以先去掉testfile文件的写权限,命令如下。

再执行以上代码。

也可以使用相同的except语句来处理多个异常信息,示例如下。

例如:

当在try块中抛出一个异常时,立即执行finally块代码。finally块中的所有语句执行后,异常被再次触发,并执行except块代码。

可以使用raise语句自己触发异常,raise语法格式如下。

语句中Exception是异常的类型(例如NameError),参数是一个异常参数值。该参数是可选的,如果不提供,异常的参数是None。最后一个参数是可选的(在实践中很少使用),如果存在,则是跟踪异常对象。

一个异常可以是一个字符串、类或对象。Python的内核提供的异常,大多数都是实例化的类,可以理解为一个类的实例的参数。

定义异常的方法非常简单,示例如下。

需要注意的是,为了能够捕获异常,except语句必须用相同的异常来抛出类对象或者字符串。

例如,捕获以上异常,except语句如下所示。

例如:

执行以上代码,输出结果如下。