Python网络爬虫与数据分析从入门到实践
上QQ阅读APP看书,第一时间看更新

1.2 Python语法入门

本节开始讲解Python的基本语法,包括变量、数据类型、分支和循环语句等,这是学习Python编程的基础,请读者务必熟练掌握。

在讲解Python的语法前,先讲一个知识点,在Python语法里,是通过缩进来定义代码的层次结构的,即同一层次的代码都向左对齐,而下一个层次的代码块会有4个空格的缩进。

不同层次代码块缩进的空格数是约定俗成的,当然如果缩进空格数是3或者5也可以,最好做到整个程序统一,否则会降低代码的可读性,并会给维护代码的工作带来一定的难度。

1.2.1 Python常量和变量

一种编程语言通常会有常量和变量,Python语言也不例外。在Python语言中,常量就是其值不变的量,例如:数字、字符串、布尔值、空值就是常量。

变量则是在程序运行过程中,其值可以变化的量。Python变量占用内存一块空间,用来存放变量的值(或地址),存放的值是可以发生改变的。

每一个Python变量都有一个名字,并严格遵循变量的命名规则:

(1)变量名必须以字母或下画线开头(但以下画线开头的变量在Python中还有特殊含义,请注意),不得使用中文或数字开头。

(2)变量名中不能有空格或标点符号(如逗号、括号、斜线、反斜线、引号、问号、冒号、句号等)。

(3)不能使用关键字作为变量名,也不建议使用系统内置的模块名、函数名、类型名作为变量名,如果这样做可能会导致代码无法运行。例如,不能使用input作为变量名,因为input()是一个输入函数。

(4)变量名区分英文字母的大小写,如name和Name是不同的变量。

(5)每个变量在使用前都必须赋值,变量赋值以后才会被创建,给变量赋值可以使用任意类型的数据。例如,Name="wang kai"(创建一个字符串变量);y_1=39(创建一个整型变量)。

1.2.2 基本数据类型

开发Python程序时,不免要和各种数据类型打交道,常见的数据类型有整型、浮点型、字符串类型和布尔型。在如下的SimpleData.py范例程序中演示了对各种基本数据类型数据的操作。

在解析上述程序代码前,请读者注意两点:第一,由于在本程序中的所有代码都是处于同一层次,所以均是靠左对齐,且没有缩进;第二,在诸如第2行和第4行的后面,我们是用“#”作为前导符来编写单行的注释。

第1行代码定义了一个整型变量times,并将16赋值给该变量。在第2行的print语句中,对times进行了加1操作,所以输出结果是17。在第3行的val变量数值之前,使用0x前缀表示该数值为十六进制。第4行的打印语句输出该变量的值应该是255。

第5行代码定义的price变量带有小数点,这种数据类型是浮点型数据,除了直接用小数点定义外,还可以用带e的科学记数法的方式来定义,比如第7行通过3e5定义了光的速度,单位是千米,表示的数字是3后面带5个零,在第9行通过1e-9定义了1纳米的长度,具体的数量级是1乘以10的-9次方。

在第11行代码中,isExpensive变量的值是布尔值True,因为price小于30,从第12行的输出语句的输出结果可以得知,最终输出的是True。可以直接把True或False赋值给布尔类型变量,也可以采用类似第11行代码的方式—通过表达式的运算结果来赋值。

以上范例程序演示了基本数据类型的运算或操作。请注意,由于在Python程序里定义变量时无须指定该变量的数据类型,比如在第1行定义times时无须用int times=16的方式来声明变量的数据类型,在Python语言中,将16赋值给times变量就已经表示times即被定义为整型变量。

另外,在Python中定义变量时,变量名尽量要有含义,比如从第5行定义的变量名price,我们就能看出它是“价格”的意思,不建议用a或者b之类无具体含义的字母作为变量名来定义变量。

1.2.3 字符串

在Python语言中,可以用单引号和双引号来定义字符串。

Python提供了若干可供调用的操作字符串的方法(method),以下我们通过StringDemo.py范例程序学习字符串的常见用法。

本范例程序的第1行代码通过单引号的方式创建了名为logMsg的字符串变量。第2行代码通过“+”这个运算符实现了字符串串接的操作,请注意在第2行代码中待串接的字符串是用双引号定义的。随后通过第4行的输出语句输出串接两个字符串后的结果。

第5行代码在给twoLineStr字符串变量赋值的字符串中引入了“\n”这个换行符,通过第6行的输出语句,我们能看到对应的换行效果。如果把其中的“\n”换成“\t”,就能看到引入制表符(Tab字符)的空格效果。“\n”和“\t”叫作转义字符,也是加“\”来表示常见的那些不能显示的ASCII字符,除了“\n”和“\t”,还有其他的转义符。

在第7行代码里调用了len方法获得字符串的长度然后打印输出。第8行代码通过replace方法替换源字符串中子字符串,该方法中的第一个参数表示待替换的子字符串,第二个参数表示用于替换的子字符串,该句的输出结果是for Strforg.py,connect Str,源字符串中的“in”都被替换成“for”。

第9行和第10行代码演示了通过find方法查找特定字符或字符串的用法,其中第9行是在logMsg字符串变量里查找“String”子字符串,返回结果是3,表示在源字符串的索引位置3找到了(其实是第4个字符位置,因为字符串索引值从0开始),而第10行是查找“Exist”子字符串,因为在源字符串中没找到,所以返回-1。

第11行和第12行代码给出的index方法也能起到查找的作用,与find方法的区别是,如果在index语句里出现类似第12行没找到的情况,不会像find方法那样返回-1,而是会抛出异常。对应地,如果去掉第12行注释语句的前导符“#”使该行语句变为可执行,那么就能看到“由于没找到所以抛出异常”的情况。

上述范例程序演示了字符串的常用操作。在项目的实际应用中,经常还需要对字符串进行分片操作,在如下的StrSplit.py范例程序中演示了如何使用分片操作。

在Python中会用[起始值:终止值]的方式对字符串执行分片操作,其含义是,根据[起始值:终止值]的值来截取(分片)相应的字符串,字符串中的字符使用索引值来引用,字符串的第一个字符的索引值为0,以此类推。

以下我们来分析上述程序代码执行分片操作的具体方法。

用法1:如第2行和第3行代码那样,[]运算中的起始值和终止值都有值,且为正数。索引值从0开始,在字符串“in String.py”中第一个字符“i”的索引值是0,索引值为4的字符是“t”。在具体分片截取字符串的时候,得到的子字符串包含起始索引值对应的字符,但不包含终止索引值对应的字符,因此第2行语句分片得到的字符串为“in S”,同理第3行语句分片得到的结果为“n S”。

用法2:如第4行和第5行代码那样,[]运算中的起始值和终止值中只有一个有值,且为正数。比如第4行语句中起始值空缺,这表示从默认的起始位开始分片。而第5行只有起始值,这表示分片的结束默认在字符串的结尾。因此,第4行语句得到的字符串是“in St”,第5行语句得到的字符串是“py”。

用法3:如第6行代码,只有一个值,这表示只截取该索引值指定的字符,这里值是-1,负号表示从字符串右边开始计算,-1则表示截取字符串右边的第1个字符,因而结果是“y”。

用法4:如第7行代码,起始值和终止值中有一个值是负数。因为负数表示从字符串的右边开始计算,这里的“5:-3”表示从第5个索引值位置开始,包含索引值是5的字符,截取到从字符串右边算起第3个字符,因而结果是“ring”。

注意

执行分片操作后的新字符串和原字符串就没有关联了,对其中一个字符串进行操作不会影响到另一个字符串,比如第8行代码,对字符串变量str进行分片的结果是创建了新字符串变量newStr,在第9行里调用replace方法对原字符串进行了替换操作,但从第10行语句输出新字符串的结果上来看,新字符串并没有受字符串替换的影响。

1.2.4 单行注释和多行注释

前面讲述了在Python程序中注释的用法。可用“#”号进行单行注释,如果要注释多行,则可以用一对“' ' '”(三个单引号)。在如下的MoreLineComment.py范例程序中,不仅演示了多行注释的效果,还演示了在注释中包含中文的方式。

本范例程序第1行代码的作用是表示本段程序代码采用utf-8的编码方式。如果要在程序代码中使用中文,则需要加上如第1行所示的表明采用何种编码的语句。

从第2行到第5行代码用一对“' ' '”标注了多行中文注释,请注意多行注释需要以“' ''”开始,也要以“' ' '”结尾。在第7行里,通过print语句输出了中文,在控制台里就能看到中文。

1.2.5 条件分支语句

在Python程序中,可以用if…elif…else的语法来编写程序中的条件分支语句,具体的语法如下:

在上述代码块中,if和elif语句后面都跟着判断条件,条件判断的结果为布尔值,如判断条件的结果为true,则执行其后代码块所包含的语句。

如果if或elif的判断条件的结果都不是true,那么会执行else后面代码块所包含的语句。使用if分支语句时,请注意两点:第一,if、elif和else语句之后,均需要带“:”冒号;第二,由于Python是采用缩进方式来表示程序中代码的层次关系,因此if、elif和else之后的语句都需要缩进以表示各自所属的代码块层次。在如下的IfDemo.py范例程序中以判断闰年来演示相关条件分支语句的用法。

年份能被4整除但不能被100整除,或者能被400整除的,都是闰年。照此规则,首先在第3行的if语句中让year取400的余数,如果能被400整除,则在第4行编写打印语句以输出“是闰年”的提示信息。

如果无法被400整除,则执行第5行的elif流程,判断年份能否被4整除且不能被100整除,如果满足此条件,也是闰年。如果不满足第3行和第5行的if和elif条件,则执行第7行的else流程,在第8行输出“不是闰年”的提示信息。

在本范例程序中,由于2022不能被400整除且不能被4整除(不能被4整除,就不用判断是否非100的倍数),因此会执行第8行的语句输出“不是闰年”的提示信息。

1.2.6 循环语句

在Python程序中可以通过for和while实现程序的循环执行,其中通过for语句,能依次遍历元素中的所有项,在如下的ForDemo.py范例程序中演示了相关用法。

本范例程序的第1行代码定义了一个字符串,随后用第2行和第3行的for循环语句,遍历并输出了这个number字符串变量中的字符。请注意,第2行的for语句后面同样要带上冒号。

在第5行开始的for循环中,遍历了第4行定义的languageArr对象,第6行的输出语句会输出“Python”“C#”“Java”和“Go”字符串,它们都是换行输出(也就是每个字符串独占一行)。

Python语言中while的语法如下所示:

如果第1行的判断条件的结果为True,就执行其后循环代码块中的语句,否则就退出while循环。

在如下的WhileDemo.py范例程序中,通过while语句计算1到101所有奇数的和。

本范例程序在第3行的while语句中,循环的条件是num≤101,即num值小于等于101时,会执行第4行到第6行的代码块(即循环体)。在该while循环的代码块中,第4行执行奇数累加的运算,在第5行执行对num的加2运算。该范例程序运行结束时,我们可以看到第7行输出的奇数和为2601。

在使用while循环语句时请注意如下两点:第一,在循环体内需要像第5行那样更新循环的条件值,如果不更新,就会出现死循环的现象;第二,注意边界值,比如若去掉第6行的注释符号,就能确认最后一个被相加的奇数是101,但如果在第3行的while语句中,不慎将条件语句错写成while num <101,那么只会累加1到99的奇数和,导致程序出现逻辑错误,得出错误的答案。

1.2.7 break和continue

在for和while循环语句中,可以使用break语句终止循环,在下面的BreakDemo.py范例程序中可以看到具体的用法。

本范例程序在第2行到第5行的for循环中,依次遍历第1行定义的languageArr变量中的元素。遍历时会通过第4行的if语句判断当前元素是否等于字符串'Python',如果相等,则执行第5行的break语句退出for循环。

运行上述范例程序后,我们会发现该程序的输出结果中不包含'Go'字符串,则说明当遍历到'Python'元素时,就已经退出了for循环,不再继续遍历后面的'Go'元素。

执行break语句可以退出当前所在循环的循环体,而执行continue语句则可以退出当前循环体本轮次的循环。下面通过ContinueDemo.py范例程序中来看看continue语句的用法。

本范例程序的第3行的条件判断语句,如果当前遍历到的元素是'C++',就会执行第4行的continue语句结束本轮次的循环,继续下一轮次的循环,而不是退出当前的整个for循环体。

结束本轮次的循环后,会继续遍历后继的'Python'和'Go'这两个元素,所以该范例程序的输出结果中会包含除了'C++'元素之外的其他三个元素。

1.2.8 格式化输出

在前面的章节中给出了print打印语句的用法,在实际项目中,print语句更常见的用法是进行格式化输出。下面的PrintDemo.py范例程序演示了格式化输出。

本范例程序第2行的print语句中,%s表示以字符串的形式输出指定参数,第1行注解中的文字信息就是第2行print语句的输出结果,由此可知,第2行中的两个%s均被其之后由%指定的两个参数所替代。

第4行的代码演示了%s、%d和%f的综合用法,其中%d表示格式化输出整型数据,%f表示格式化输出浮点型数据。同样地,它们会被%后指定的参数所替代。第3行注释中的信息就是第4行print语句的输出结果,由此可知,%f可以用来指定浮点数输出的格式,如果要指定小数点后面的位数,可以如第6行那样,用%.2f的方式指定浮点数的输出格式,即输出时保留2位小数。

第8行通过%e以科学记数法的格式输出数据,第7行注释中的信息就是输出结果。

虽然在Python语言中还有其他格式化输出语句,但是在上述范例程序化中给出的格式化输出字符串、数字、浮点数和科学记数法的用法是比较常见的,其他不太常用的用法,本书就不再赘述了。