第一章 基础

注释规则

Python中有两种主要的注释方式:单行注释和多行注释。

1
2
3
4
# 这是单行注释
'''这是
多行注释
'''

代码缩进

Python中使用代码缩进和冒号 :区分代码之间的层次。对于类定义、函数定义、流程控制语句,以及异常处理语句等,行尾的冒号和下一行的缩进表示一个代码块的开始,而缩进结束,则表示一个代码块的结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
height = float(input('请输入身高:'))
weight = float(input('请输入体重:'))
bmi = weight / (height * height)
print('您的BMI值为:', bmi)

# 判断身材是否合理
if bmi < 18.5:
print('您的身材过轻')
elif bmi < 24:
print('您的身材正常')
elif bmi < 27:
print('您的身材过重')
elif bmi < 30:
print('您的身材肥胖')
else:
print('您的身材严重肥胖')

代码规范

  1. 编写规则
    • 每个 import语句只导入一个模块
    • 不要在行尾添加分号 ;
  2. 命名规范
    • 模块名尽量短小,并且全部使用小写字母,单词之间用下划线连接
    • 包名尽量短小,并且全部使用小写字母
    • 类名采用驼峰命名法,每个单词的首字母大写

说明

在python语言中,使用内置函数 type()可以返回变量的类型。

在Python语言中,使用内置函数 id()可以返回变量所指的内存地址。

第二章 条件表达式

1
2
3
4
5
6
7
x = 10
y = 20
if x > y:
z = x
else:
z = y
print(z)

上述代码可以进行简化,如下:

1
2
3
4
x = 10
y = 20
z = x if x > y else y
print(z)

==而在C语言中,可以使用三目运算符进行简化:==

1
2
3
4
int x = 10;
int y = 20;
int z = x > y ? x : y;
printf("%d", z);

第三章 流程控制

选择语句

Python语言中,使用 ifelifelse语句进行流程控制。Python中==没有 switchcase语句。==

==在Python中,else语句并不遵循如C语言的最近原则,而是与相同缩进量的代码块进行匹配。例如:==

1
2
3
4
5
6
a = -1
if a >= 0:
if a > 0:
print("a大于零")
else:
print("a等于零")

将不输出任何提示信息,这是因为 else语句属于第三行的 if语句,所以当 a小于零时,else语句将不执行。

循环语句

Python语言中,使用 for循环和 while循环进行流程控制。Python中==没有 do...while循环。==

  1. while循环语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    while 条件循环体:
    循环体语句
    # 例如
    while True:
    number += 1
    if number % 3 == 2 and number % 5 == 3 and number % 7 == 2:
    print(number)
    break

    使用 while循环语句时,需要注意循环条件的设置,避免出现死循环。

  2. for循环语句

    1
    2
    for 迭代变量 in 对象:
    循环体语句

    其中,迭代变量用于保存读取出的值;对象为要遍历或迭代的对象,该对象可以是任何有序的序列对象,如字符串、列表和元组等;循环体为一组被重复执行的语句。

    1
    2
    3
    4
    5
    # 计算1到100的数字和
    sum = 0
    for i in range(101):
    sum += i
    print(sum)

    上述代码使用了 range()函数,其语法格式如下:

    1
    range(start, end, step)

    其中,start为可选参数,指定起始值,默认为0;end为必填参数,指定结束值,不包含在范围内;step为可选参数,指定步长,默认为1。

    如果只填一个参数,即为 range(end),则起始值为0,步长为1。如果填两个参数,即为 range(start, end),则步长为1。

    例如使用 for循环语句输出20以内的奇数:

    1
    2
    for i in range(1, 20, 2):
    print(i, end = ' ')

    Python中 print()函数每次输出后都会换行,如果想让 print()函数不换行,在一行上输出多个内容时,用逗号 ,隔开各个内容,或使用对单个内容使用 print(i, end = '分隔符')格式

    其中,end参数用于指定输出结束时的分隔符,默认为换行符 \n。如果将 end参数设置为空字符串 '',则输出结束时不添加任何分隔符,所有内容都在一行上输出。

    for循环还可以逐个遍历字符串,例如:

    1
    2
    3
    print("Hello World!")
    for ch in 'Hello World!':
    print(ch)

    1
    2
    3
    4
    string = 'Hello World!'
    print(string)
    for ch in string:
    print(ch)

    两段代码输出结果一致,都是先横向输出再纵向输出。

  3. 嵌套循环

    循环呗,for循环可以嵌套使用,while循环也可以嵌套使用,for循环和 while循环可以根据需要进行嵌套使用。

    使用嵌套的 for循环语句打印九九乘法表:

    1
    2
    3
    4
    for i in range(1,10):
    for j in range(1,i+1):
    print(str(j) + "*" + str(i) + "=" + str(i*j) + "\t",end="")
    print('')

    输出结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    1*1=1
    1*2=2 2*2=4
    1*3=3 2*3=6 3*3=9
    1*4=4 2*4=8 3*4=12 4*4=16
    1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
    1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
    1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
    1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
    1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81

breakcontinuepass语句

  1. break语句

    break语句可以终止当前的循环,包括 for循环和 while循环。

    break语句一般会结合 if语句进行搭配使用,表示在某种条件下跳出循环。如果使用嵌套循环,break语句将跳出最内层的循环。

  2. continue语句

    continue语句用于跳过当前循环体中剩余的语句,直接进入下一次循环。即中止本次循环而提前进入下一次循环中。

    break语句是 终止循环,而 continue语句是 中止当前循环,进入下一次循环。

    continue语句一般会结合 if语句进行搭配使用,表示在某种条件下跳过当前循环。如果使用嵌套循环,continue语句将跳过最内层的循环。

  3. pass语句

    pass语句用于占位,表示当前位置留待后续代码填充。

    1
    2
    3
    4
    5
    for i in range(1,10):
    if i % 2 ==0: # 判断是否为偶数
    print(i,end=' ')
    else: #不是偶数
    pass #占位符,不做任何事情

    输出结果为:

    1
    2 4 6 8

第四章 列表与元组

序列概述

序列是一块用于存放多个值的连续内存空间,并且按照一定顺序排列,每个值(称为元素)都分配一个数字,称为索引或位置。通过该索引可以取出相应的值。==与C语言中的数组类似但有些差别==

在Python中,序列结构主要有列表、元组、集合、字典和字符串。对于这些序列结构有以下几个通用的操作。其中,集合和字典不支持索引、切片、相加和相乘操作。

  1. 索引

    索引从0开始递增,即下标为0是第一个元素,下标为1是第二个元素,以此类推。索引越界会报错。

    Python中索引可以是负数,即从-1开始递减,-1是最后一个元素,-2是倒数第二个元素,以此类推。

  2. 切片

    切片操作是访问序列中元素的另一种方法,它可以访问一定范围内的元素。通过切片操作可以生成一个新的序列。语法格式如下:

    1
    sequence[start:end:step]

    参数说明:

    • sequence:表示序列的名称;
    • start:表示切片的起始位置(包括该位置),默认为0;
    • end:表示切片的结束位置(不包含该位置),默认为序列的长度;
    • step:表示切片的步长,默认为1。
  3. 相加

    在Python中,使用 +运算符可实现多种相同类型的序列相加操作,即将两个序列相加,生成一个新的序列,但不去除重复的元素。例如:

    1
    2
    3
    4
    verse1 = ["Hello", "World","!"]
    verse2 = ["Hello","Hao"]
    verse3 = ["Shi","jie"]
    print(verse1 + verse2 + verse3)

    输出结果为:

    1
    ['Hello', 'World', '!', 'Hello', 'Hao', 'Shi', 'jie']

    在进行序列相加时,相同类型是指同为列表、元组、字符串等,序列中的元素类型可以不同。但是不能是列表与元组相加,或是列表与字符串相加。

  4. 相乘

    在Python中,使用 *运算符实现序列的复制操作,即将一个序列复制指定次数,生成一个新的序列。例如:

    1
    2
    verse1 = ["Hello", "World","!"]
    print(verse1 * 3)

    输出结果为:

    1
    ['Hello', 'World', '!', 'Hello', 'World', '!', 'Hello', 'World', '!']
  5. 检查某个元素是否是序列的成员(元素)

    innot in关键字用于判断某个元素是否在序列中。其语法格式如下:

    1
    value in sequence

    其中,value表示要检查的元素,sequence表示指定的序列。

    例如:

    1
    2
    3
    verse1 = ["Hello", "World","!"]
    print("Hello" in verse1)
    print("Hao" not in verse1)

    输出结果为:

    1
    2
    True
    True
  6. 计算序列的长度、最大值和最小值

    len()函数用于计算序列的长度,max()函数用于计算序列中的最大值,min()函数用于计算序列中的最小值。例如:

    1
    2
    3
    4
    num = [1,78,82,15161,115,10,11]
    print(len(num))
    print(max(num))
    print(min(num))

    输出结果为:

    1
    2
    3
    7
    15161
    1

列表

列表是一种有序的、可变的序列结构,用于存放多个值。列表中的元素可以是不同类型的数据,包括数字、字符串、布尔值,甚至是其他列表,很灵活。

Python中的列表使用方括号 [] 来定义,列表中的元素之间用逗号隔开。

  1. 创建和删除列表

    • 使用赋值运算直接创建列表

      语法格式:

      1
      list_name = [element1, element2, ..., elementN]

      其中,list_name表示列表的名称,element1element2、…、elementN表示列表中的元素。

    • 创建空列表

      语法格式:

      1
      list_name = []

      其中,list_name表示列表的名称。

    • 创建数值列表

      在Python中,数值列表很常用。例如在考试系统中记录学生的成绩,在游戏中记录每个角色的位置、各个玩家的得分情况等等。在Python中,可以使用 list()函数创建数值列表。语法格式如下:

      1
      list(data)

      其中,data表示要转换为列表的数据,例如一个元组、一个字符串、一个范围等。例如:

      1
      2
      num = list(range(1,10))
      print(num)

      输出结果为:

      1
      [1, 2, 3, 4, 5, 6, 7, 8, 9]
    • 删除列表

      对于已经创建的列表,可以使用 del关键字删除列表。语法格式如下:

      1
      del list_name

      其中,list_name表示要删除的列表的名称。

      注意:删除列表后,列表中的元素将无法再访问。在实际开发中,del语句并不常用。因为Python自带的垃圾回收机制会自动销毁不用的列表。

  2. 访问列表元素

    输出也简单,可以直接使用 print()函数。例如:

    1
    print(listname)

    也可以通过索引获取指定的元素。例如:

    1
    print(listname[0])

    输出结果为:

    1
    element1

    其中,element1表示列表中的第一个元素。

  3. 遍历列表

    • 直接使用 for循环实现
      语法格式如下:

      1
      2
      for item in list_name:
      print(item)

      其中,list_name表示要遍历的列表的名称,item用于保存获取到的元素值。

      使用 for循环和 enumerate()函数实现:

      1
      2
      for index, item in enumerate(list_name):
      print(index, item)

      其中,index表示元素的索引,item表示元素的值。

  4. 添加、修改和删除列表元素

    • 添加元素

      使用 append()方法在列表的末尾添加元素。语法格式如下:

      1
      list_name.append(element)

      其中,list_name表示要添加元素的列表的名称,element表示要添加的元素。

      使用 insert()方法在指定位置添加元素。语法格式如下:

      1
      list_name.insert(index, element)

      其中,list_name表示要添加元素的列表的名称,index表示要添加元素的位置,element表示要添加的元素。

      上述是想列表中添加一个元素,如果想将一个列表中的全部元素添加到另一个列表中,可以使用列表对象的 extend()方法。语法格式如下:

      1
      list_name.extend(another_list)

      其中,list_name表示要添加元素的列表的名称,another_list表示要添加的列表。another_list中的所有元素都将添加到 list_name的末尾。

    • 修改元素

      要修改列表中的元素,直接通过索引赋值即可。例如:

      1
      list_name[index] = new_element

      其中,list_name表示要修改元素的列表的名称,index表示要修改元素的位置,new_element表示新的元素值。

    • 删除元素

      删除元素主要有两种情况,一种是根据索引删除,另一种是根据元素值删除。

      • 根据索引删除元素

        删除列表中的指定元素和删除列表类似,也可以使用 del关键字。语法格式如下:

        1
        del list_name[index]

        其中,list_name表示要删除元素的列表的名称,index表示要删除元素的位置。

      • 根据元素值删除元素

        要删除列表中的指定元素值,需要使用列表对象的 remove()方法。语法格式如下:

        1
        list_name.remove(element)

        其中,list_name表示要删除元素的列表的名称,element表示要删除的元素值。

  5. 对列表进行统计计算

    • 获取指定元素出现的次数

      使用列表对象的 count()方法获取列表中指定元素的出现次数。语法格式如下:

      1
      list_name.count(element)

      其中,list_name表示要统计元素的列表的名称,element表示要统计的元素值,这里只能精确匹配,不能是元素值的一部分。

    • 获取指定元素首次出现时的下标

      使用列表对象的 index()方法获取列表中指定元素首次出现的位置。语法格式如下:

      1
      list_name.index(element)

      其中,list_name表示要查找元素的列表的名称,element表示要查找的元素值,这里只能精确匹配,不能是元素值的一部分。如果列表中不存在该元素,则会抛出 ValueError异常。

    • 统计数值列表的元素和

      使用列表对象的 sum()方法统计列表中的元素和。语法格式如下:

      1
      sum(list_name)

      其中,list_name表示要统计元素和的数值列表的名称。

  6. 列表排序

    Python中提供了两种常用的对列表进行排序的方法。

    • 使用列表对象的 sort()方法
      语法格式如下:

      1
      listname.sort(key=None, reverse=False)

      其中,listname表示要排序的列表的名称,key表示排序的关键字,reverse表示是否按降序排序。如果不指定 key,则默认按元素值的大小排序。如果指定 key,则根据 key函数的返回值进行排序。如果 reverseTrue,则按降序排序;否则按升序排序。

      使用 sort()方法进行数值列表的排序比较简单,但是对字符串列表进行排序时,采用的规则是先对大写字母进行排序,然后再对小写字母进行排序。如果想要对字符串列表进行排序(不区分大小写时),需要指定其 key参数。例如:

      1
      list_name.sort(key=str.lower)

      其中,list_name表示要排序的字符串列表的名称。key=str.lower表示将列表中的元素转换为小写字母进行排序,即不区分字母大小写。

      对中文内容的列表进行排序时,需要使用第三方库如 pypinyin来实现,不能直接使用 sort()方法。

    • 使用内置的 sorted()函数

      使用 sort()方法排序后,原列表将被修改,排序后的结果将直接存储在原列表中。如果不希望修改原列表,可以使用 sorted()函数进行排序。语法格式如下:

      1
      sorted(list_name, key=None, reverse=False)

      其中,list_name表示要排序的列表的名称,key表示排序的关键字,reverse表示是否按降序排序。如果不指定 key,则默认按元素值的大小排序。如果指定 key,则根据 key函数的返回值进行排序。如果 reverseTrue,则按降序排序;否则按升序排序。

  7. 列表推导式

    列表推导式是一种创建列表的简写方式,可以快速生成一个列表,或者根据某个列表生成满足指定要求的列表。通常有以下几种常用的语法格式。

    • 生成指定范围的数值列表

      语法格式如下:

      1
      listname=[expression for var in range(start, stop, step)]

      其中,expression表示要生成的元素的表达式,var表示迭代变量,start表示范围的起始值(包含),stop表示范围的结束值(不包含),step表示步长(默认为1)。

      例如要生成一个包括10个随机数的列表,要求数的范围在1到100之间(包含1和100),可以使用以下代码:

      1
      2
      import random
      listname=[random.randint(1,100) for i in range(10)]
    • 根据已有列表生成新的列表

      语法格式如下:

      1
      listname=[expression for var in oldlist if condition]

      其中,expression表示要生成的元素的表达式,var表示迭代变量,其值为后面列表的每个元素值,oldlist表示原列表的名称,condition表示筛选条件(可选)。

      例如要根据一个列表生成一个新的列表,要求新列表中的元素是原列表中所有偶数的平方,可以使用以下代码:

      1
      listname=[i**2 for i in old_list if i%2==0]

      其中,old_list表示原列表的名称。

  8. 二维列表

    二维列表中的信息以行和列的方式存储,行和列的索引从0开始,第一个下标为行索引,第二个下标为列索引。

    在Python中,创建二维列表有以下三种常用的方法。

    • 直接定义二维列表

      在Python中,二维列表就是包含列表的列表。即一个列表中的每个元素又是一个列表,每个子列表表示二维列表中的一行。例如:

      1
      listname=[[1,2,3],[4,5,6],[7,8,9]]

      其中,listname表示二维列表的名称,[1,2,3][4,5,6][7,8,9]分别表示二维列表中的三行。

    • 使用循环嵌套创建二维列表

      创建二维列表,可以使用嵌套的 for循环实现。例如:

      1
      2
      3
      4
      5
      arr=[]                  # 创建一个空列表
      for i in range(4): # 循环4次,每次创建一个新的空列表
      arr.append([])
      for j in range(5): # 循环5次,每次向内层列表中添加一个元素
      arr[i].append(j)
    • 使用列表推导式创建二维列表

      创建二维列表,可以使用列表推导式实现。例如:

      1
      arr=[[j for j in range(5)] for i in range(4)]

      其中,arr表示二维列表的名称,4表示二维列表的行数和列数。

    创建二维列表之后,可以通过以下语法访问二维列表中的元素:

    1
    arr[i][j]

    其中,i表示行索引,j表示列索引。

元组

元组是一种不可变(immutable)的数据结构,即一旦创建后,就不能修改。元组中的元素可以是任意类型的数据,包括数字、字符串、布尔值、列表、元组等。

  1. 元组的创建和删除

    • 使用赋值运算符直接创建元组
      语法格式如下:

      1
      tuple_name=(element1,element2,element3,...)

      其中,tuple_name表示元组的名称,element1,element2,element3,...表示元组中的元素。

      例如以下:

      1
      2
      num = (1,2,3,4,5,6,7,8,9,10)
      nihao = ("Hello","World!")

      如果要创建的元组只包括一个元素,则需要在定义元组时,在元素的后面加一个逗号 ,,否则Python会将该元素视为一个普通的变量,而不是元组。例如:

      1
      tuple_name=(element,)
    • 创建空元组

      1
      empty_tuple = ()

      空元组可以应用在为函数传递一个空值或者返回空值时。

    • 创建数值元组
      在Python中,可以使用 tuple()函数创建一个数值元组。语法格式如下:

      1
      tuple_name=tuple(iterable)

      其中,tuple_name表示元组的名称,iterable表示可迭代对象,例如列表、元组、字符串等。

      例如要创建一个包括10个随机数的元组,要求数的范围在1到100之间(包含1和100),可以使用以下代码:

      1
      tuple_name=tuple(range(1,101))
    • 删除元组
      对于已经创建的元组,不在使用时,可以使用 del关键字删除元组。语法格式如下:

      1
      del tuple_name

      其中,tuple_name表示要删除的元组的名称。

      del语句在实际开发中并不常用。Python自带的垃圾回收机制会自动销毁不用的元组。

  2. 元组的访问

    可以直接使用 print()函数打印元组中的元素。例如:

    1
    2
    print(num)
    print(nihao)

    也可以使用切片:

    1
    print(num[:3])  # 打印num中的前3个元素

    同样,元组可以使用 for循环进行遍历:

    1
    2
    3
    coffee = ("蓝山","普洱","拿铁","瑞幸")
    for i in coffee:
    print(i + "咖啡",end=" ")

    输出结果为:

    1
    蓝山咖啡 普洱咖啡 拿铁咖啡 瑞幸咖啡

    元组还可以使用 for循环和 enumerate()函数进行遍历,同时获取元素的索引。例如:

    1
    2
    for i,item in enumerate(coffee):
    print(i,item)

    输出结果为:

    1
    2
    3
    4
    0 蓝山
    1 普洱
    2 拿铁
    3 瑞幸
  3. 元组的修改

    元组是不可变的,不能修改。如果需要修改元组中的元素,则需要创建一个新的元组,将修改后的元素添加进去。例如:

    1
    2
    coffee = ("蓝山","普洱","拿铁","瑞幸")
    coffee = ("蓝山","普洱","卡布奇诺","瑞幸","库迪")

    还可以对元组进行连接组合,例如:

    1
    2
    coffee = ("蓝山","普洱","拿铁","瑞幸")
    coffee = coffee + ("卡布奇诺","库迪")

    输出结果为:

    1
    ('蓝山', '普洱', '拿铁', '瑞幸', '卡布奇诺', '库迪')

    注意:在进行元组连接时,连接内容必须都是元组。不能将元组和字符串或者列表进行连接。如果要连接的元组只有一个元素,一定不要忘记后面的逗号。

  4. 元组推导式

    使用元组推导式可以快速生成一个元组,它的表现形式和列表推导式类似,只是将 []换成 ()。例如:

    1
    2
    num = (i for i in range(10))
    python(num)

    输出结果为:

    1
    <generator object <genexpr> at 0x0000017FAFDB5B40>

    可以看出,元组推导式返回的是一个生成器对象。这与列表推导式不同。要使用该生成器对象,需要将其转换为元组或列表。使用 tuple()函数可以将生成器对象转换为元组,使用 list()函数可以将生成器对象转换为列表。例如:

    1
    2
    3
    num = (i for i in range(10))
    num = tuple(num)
    print(num)

    输出结果为:

    1
    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  5. 元组与列表的区别

    简单理解:列表类似于我们用铅笔在纸上写下自己喜欢的歌曲,写错了还能擦掉。而元组则类似与用钢笔写下的歌曲名字,写上了就擦不掉了,除非换一张纸重写。

    主要有以下5个方面:

    1. 列表属于可变序列,它的元素可以随时修改或者删除。元组属于不可变序列,它的元素不能修改,除非整体替换。
    2. 列表可以使用 append()insert()remove()pop()等方法对元素进行添加、插入、删除、弹出等操作。而元组则不能使用这些方法。
    3. 可以使用切片访问和修改列表的元素,但是不能使用切片修改元组中的元素,只能访问。
    4. 元组比列表的访问和处理速度快。所以如果只需要对其中的元素进行访问而不进行修改,推荐使用元组。
    5. 列表不能作为字典的键,元组可以。

第五章 字典与集合

字典

字典是一种无序的、可变的、以键值对(key-value)形式存储数据的数据结构。每个键(key)与一个值(value)相关联,通过键可以快速访问对应的值。字典中的键必须是唯一的,而值可以是任意类型的数据。

  1. 创建和删除字典

    创建字典的语法格式为:

    1
    dict_name = {key1:value1,key2:value2,...}

    其中,dict_name表示字典的名称,key1, key2, … 表示字典中的键,必须是唯一的,且不可变;value1, value2, … 表示字典中的值,可以是任何数据类型,不是必须唯一的。

    同列表和元组一样,也可以创建空字典:

    1
    dictionary = {}

    或者

    1
    dictionary = dict()

    Python的 divt()方法除了可以创建一个空字典外,还可以通过已有数据快速创建字典。只要有以下两种形式:

    • 通过映射函数创建字典:

      1
      dictionary = dict(zip(key_list,value_list))

      dictionary表示字典的名称,zip()函数用于将多个列表或元组对应位置的元素组合为元组,并返回包含这些内容的 zip对象。如果想得到元组,可以将 zip对象使用 tuple()函数转换为元组;如果想得到列表,可以将 zip对象使用 list()函数转换为列表。

      key_list表示字典中的键的列表,value_list表示字典中的值的列表。如果二者长度不一致,则以最短的列表为准。

    • 通过给定的键值对创建字典:

      1
      dictionary = dict(key1=value1,key2=value2,...)

      dictionary表示字典的名称,key1, key2, … 键值对中的键必须是唯一的,且不可变;value1, value2, … 键值对中的值可以是任何数据类型,不是必须唯一的。

      例如:

      1
      dictionary = dict(姓名="张三",年龄=18,性别="男")

      在Python中,还可以使用 dict对象的 fromkeys()方法创建值为空的字典:

      1
      2
      list = ["姓名","年龄","性别"]
      dictionary = dict.fromkeys(list)

      输出结果为:

      1
      {'姓名': None, '年龄': None, '性别': None}

      其中,None表示字典中的值,默认值为 None。如果要指定其他默认值,只需要在方法中添加第二个参数即可。例如:

      1
      dictionary = dict.fromkeys(list,"未知")

      输出结果为:

      1
      {'姓名': '未知', '年龄': '未知', '性别': '未知'}

    同列表和元组一样,字典也可以使用 del关键字删除:

    1
    del dictionary

    其中,dictionary表示要删除的字典

    另外,字典也可以使用 clear()方法清空:

    1
    dictionary.clear()
  2. 字典的访问

    直接输出:

    1
    print(dictionary)

    不过一般很少直接输出字典的内容,而是需要根据指定的键得到相应的结果。

    1
    print(dictionary["姓名"])

    如果键不存在,Python会抛出一个 KeyError异常。这时我们可以使用 if语句对不存在时的情况进行处理:

    1
    print("他的名字是:", dictionary["姓名"] if "姓名" in dictionary else "没有这个键")

    另外,Python提供了 get()方法,它可以返回指定键对应的值,如果键不存在,则返回一个默认值。语法格式如下:

    1
    dictionary.get(key,default_value)

    其中,key表示要获取的键,default_value表示如果键不存在时的默认值。
    例如:

    1
    print("他的名字是:", dictionary.get("姓名","没有这个键"))
  3. 遍历字典

    使用字典对象的 item()方法可以获取字典的键值对列表。语法格式如下:

    1
    dictionary.items()

    例如:

    1
    2
    3
    dictionary = {"姓名":"张三","年龄":18,"性别":"男"}
    for i in dictionary.items():
    print(i)

    输出结果为:

    1
    2
    3
    ('姓名', '张三')
    ('年龄', 18)
    ('性别', '男')

    如果想要获取到具体的每个键和值,可以使用下面的代码进行遍历:

    1
    2
    3
    dictionary = {"姓名":"张三","年龄":18,"性别":"男"}
    for key,value in dictionary.items():
    print(key,"是",value)

    输出结果为:

    1
    2
    3
    姓名 是 张三
    年龄 是 18
    性别 是 男
  4. 字典的更新

    字典时可变序列,可以随时在其中添加键值对,和列表类似。向字典中添加元素的语法格式如下:

    1
    dictionary[key] = value

    由于在字典中,“键”必须是唯一的,所以如果添加的键已经存在,则更新对应的值。例如:

    1
    2
    3
    dictionary = {"姓名":"张三","年龄":18,"性别":"男"}
    dictionary["年龄"] = 20
    print(dictionary)

    输出结果为:

    1
    {'姓名': '张三', '年龄': 20, '性别': '男'}

    当字典中的某个元素不需要时,可以使用 del关键字删除:

    1
    2
    del dictionary["性别"]
    print(dictionary)

    输出结果为:

    1
    {'姓名': '张三', '年龄': 20}
  5. 字典推导式

    例如使用下面的代码生成一个包含4个随机数的字典:

    1
    2
    3
    import random
    dictionary = {i:random.randint(1,100) for i in range(1,5)}
    print(dictionary)

    输出结果为:

    1
    {1: 15, 2: 7, 3: 27, 4: 80}

    另外,使用字典推导式也可根据列表生成字典。例如:

    1
    2
    3
    4
    keys = ["姓名","年龄","性别"]
    values = ["张三",18,"男"]
    dictionary = {i+"是":j for i,j in zip(keys,values)}
    print(dictionary)

    输出结果为:

    1
    {'姓名是': '张三', '年龄是': 18, '性别是': '男'}

集合

Python集合是一种元素不可重复的序列。有可变集合(set)和不可变集合(frozenset)两种。现只介绍 set集合。集合最常用的操作就是创建集合,以及集合的添加、删除、交集、并集和差集等运算,下面进行介绍。

  1. 创建集合

    • 直接使用 {}创建集合:
    1
    setname = {element1,element2,element3,...}

    其中,element1,element2,element3,…表示集合中的元素,每个元素之间用逗号隔开。

    注意:在创建集合时,如果输入了重复的元素,Python会自动只保留一个。

    由于Python中的 set集合是无序的,所以每次输出元素时的排列顺序也可能不同。

    • 使用 set()函数创建集合:

      1
      setname = set(iterable)

      其中,iterable表示可迭代对象,可以是列表、元组、字典、字符串等。
      例如:

      1
      2
      3
      set1 = set([1,2,3,4,5])
      set2 = set(("Hello", "World"))
      set3 = set("hello")

      输出结果为:

      1
      2
      3
      {1, 2, 3, 4, 5}
      {'Hello', 'World'}
      {'e', 'l', 'o', 'h'}
  2. 集合的添加和删除

    • 添加元素

      使用 add()方法添加元素:

      1
      setname.add(element)

      其中,element表示要添加的元素。这里只能使用字符串、数字及布尔类型的True或False,不能使用列表、元组等可迭代对象。

    • 删除元素

      使用 del关键字删除整个集合,也可以使用集合的 pop()方法或 remove()方法删除一个元素,或者使用 clear()方法清空集合。

      例如:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      setname = {"C","python","Java","C++"}

      setname.remove("python")
      print(setname)

      setname.pop()
      print(setname)

      setname.clear()
      print(setname)

      输出结果为:

      1
      2
      3
      {'C', 'C++', 'Java'}
      {'C++', 'Java'}
      set()
  3. 集合运算

    集合最常用的操作就是进行交集、并集、差集和对称差集运算。

    进行交集运算时使用 &运算符,进行并集运算时使用 |运算符,进行差集运算时使用 -运算符,进行对称差集运算时使用 ^运算符。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    python = set(['张三','李四','Loris','Peter'])
    c = set(['Peter','Loris','Meg','Chris'])
    print("选择Python的人有", python)
    print("选择C语言的人有", c)
    print("交集运算", python & c) # 既选择了Python又选择了C语言的学生
    print("并集运算", python | c) # 全部学生
    print("差集运算", python - c) # 选择了Python但没有选择C语言的学生
    print("对称差集运算", python ^ c) # 选择了Python或C语言但没有同时选择两者的学生

    输出结果为:

    1
    2
    3
    4
    5
    6
    选择Python的人有 {'张三', 'Peter', 'Loris', '李四'}
    选择C语言的人有 {'Peter', 'Loris', 'Chris', 'Meg'}
    交集运算 {'Peter', 'Loris'}
    并集运算 {'Meg', 'Peter', '李四', '张三', 'Loris', 'Chris'}
    差集运算 {'张三', '李四'}
    对称差集运算 {'Meg', '李四', '张三', 'Chris'}

第六章 字符串

字符串是由一个或多个字符组成的有序序列,用于存储和表示文本数据。最早的字符串编码是美国标准信息交换码,即 ASCⅡ码。其最多只能表示256个字符,包括十个数字、大小写字母和一些其他符号。后来,我国制定了 GBK编码和 GB2312编码。UTF-8是国际通用的编码,对全世界所有国家需要用到的字符都进行了编码。

字符串编码转换

在Python中,常用的字符串类型有 strbytesstr表示Unicode字符,bytes表示二进制数据。
strbytes类型之间可以通过 encode()decode()方法相互转换。

  1. 使用 encode()方法编码

    encode()方法用于将字符串编码为二进制数据,参数为指定编码格式,默认为 UTF-8

    1
    strs.encode([encoding="UTF-8"][,errors="strict"])

    参数说明:

    • encoding:指定编码格式,默认为 UTF-8
    • errors:指定编码错误处理方式,默认为 strict,表示遇到编码错误时抛出异常。其他可选值有 ignorereplacexmlcharrefreplace等。

    例如:

    1
    2
    3
    str1 = "你好,世界!"
    bytes1 = str1.encode("GBK")
    print(bytes1)

    输出结果为:

    1
    b'\xc4\xe3\xba\xc3,\xca\xc0\xbd\xe7\xa3\xa1'
  2. 使用 decode()方法解码
    decode()方法用于将二进制数据解码为字符串,参数为指定解码格式,默认为 UTF-8

    1
    bytes.decode([encoding="UTF-8"][,errors="strict"])

    参数说明:

    • encoding:指定解码格式,默认为 UTF-8
    • errors:指定解码错误处理方式,默认为 strict,表示遇到解码错误时抛出异常。其他可选值有 ignorereplacexmlcharrefreplace等。

    例如:

    1
    2
    3
    bytes1 = b'\xc4\xe3\xba\xc3,\xca\xc0\xbd\xe7\xa3\xa1'
    str1 = bytes1.decode("GBK")
    print(str1)

    输出结果为:

    1
    你好,世界!

字符串常用操作

  1. 字符串连接

    在Python中,使用 +运算符实现字符串的连接操作,即将多个字符串连接成一个新的字符串。例如:

    1
    2
    3
    4
    verse1 = "Hello"
    verse2 = "World"
    verse3 = "!"
    print(verse1 + " " + verse2 + verse3)

    输出结果为:

    1
    Hello World!

    字符串不允许直接与其他类型的数据拼接,例如:

    1
    2
    3
    str1 = "你好,"
    num1 = 100
    print(str1 + num1)

    会抛出 TypeError异常。

    如果要将字符串与其他类型的数据拼接,可以使用 str()函数将其他类型的数据转换为字符串类型。例如:

    1
    2
    3
    str1 = "你好,"
    num1 = 100
    print(str1 + str(num1))

    输出结果为:

    1
    你好,100
  2. 计算字符串长度

    由于不同的字符所占字节数不同,所以要计算字符串的长度,需要先了解各字符所占的字节数。在Python中,数字、英文、小数点、下划线和空格占一个字节;一个汉字可能会占2~4个字节,这取决于具体编码方式。汉字在 GBK编码中占两个字节,在 UTF-8编码中占三个字节。

    Python中可以使用 len()函数计算字符串的长度。例如:

    1
    2
    str1 = "你好,世界!"
    print(len(str1))

    输出结果为:

    1
    6

    在默认情况下,len()函数计算字符串长度时,所有字符都认为是一个。

    如果要计算汉字的长度,可以使用 len()函数的 encoding参数指定编码方式,并使用 errors参数指定错误处理方式。例如:

    1
    2
    str1 = "你好,世界!"
    print(len(str1.encode("GBK")))

    输出结果为:

    1
    12
  3. 截取字符串

    字符串也属于序列,所以可以采用切片的方法实现字符串截取。语法格式如下:

    1
    string[start:end:step]

    参数说明:

    • start:指定截取的起始位置(包括该字符),默认为0。
    • end:指定截取的结束位置(不包括该字符),默认为字符串长度。
    • step:指定截取的步长,默认为1。
  4. 分割、合并字符串

    分割字符串是把字符串分割为列表,而合并字符串是将列表合并为字符串。

    字符串也可以采用 split()方法进行分割,语法格式如下:

    1
    string.split([sep=None][,maxsplit=-1])

    参数说明:

    • sep:指定分割符,默认为空格。
    • maxsplit:指定最大分割次数,默认为-1,表示不限制次数。

    例如:

    1
    2
    str1 = "你好,世界!"
    print(str1.split(","))

    输出结果为:

    1
    ['你好', '世界!']

    可以看到,split()方法将字符串根据逗号进行了分割,返回了一个包含两个元素的列表。

    如果要合并多个字符串,可以使用 join()方法。语法格式如下:

    1
    strnew=string.join(iterable)

    参数说明:

    • string:字符串类型,用于指定合并时的分隔符。
    • iterable:可迭代对象,用于指定要合并的字符串序列。

    例如:

    1
    2
    3
    list_friends = ["张三", "李四", "王五"]
    str_friends = "&".join(list_friends)
    print("你要@的好友:", str_friends)

    输出结果为:

    1
    你要@的好友: 张三&李四&王五

    可以看到,join()方法将列表中的字符串根据 &进行了合并。

  5. 检索字符串

    1. count()方法:返回字符串中指定字符出现的次数,如果不存在,则会返回0。语法格式如下:

      1
      2
      3
      4
      5
      6
      string.count(substring[,start[,end]])

      # 参数说明:
      # - `substring`:指定要检索的子字符串。
      # - `start`:指定检索的起始位置(包括该字符),默认为0。
      # - `end`:指定检索的结束位置(不包括该字符),默认为字符串长度。
      1
      2
      str1 = "你好,世界!"
      print(str1.count("好"))

      输出结果为:

      1
      1

      可以看到,count()方法返回了字符串中字符 出现的次数。

    2. find()方法:返回字符串中指定子字符串出现的位置,如果找不到,则返回-1。语法格式如下:

      1
      2
      3
      4
      5
      6
      string.find(substring[,start[,end]])

      # 参数说明:
      # - `substring`:指定要检索的子字符串。
      # - `start`:指定检索的起始位置(包括该字符),默认为0。
      # - `end`:指定检索的结束位置(不包括该字符),默认为字符串长度。
      1
      2
      str1 = "你好,世界!"
      print(str1.find("好"))

      输出结果为:

      1
      1

      可以看到,find()方法返回了字符串中子字符串 第一次出现的位置。

      在Python中,如果只是想判断指定的字符串是否存在,而不需要知道它的位置,那么可以使用 in运算符。例如:

      1
      2
      str1 = "你好,世界!"
      print("好" in str1)

      输出结果为:

      1
      True

      可以看到,in运算符返回了一个布尔值,用于判断子字符串 是否存在于字符串 str1中。

    3. index()方法:同 find()方法,但是如果找不到,则抛出 ValueError异常。语法格式如下:

      1
      2
      3
      4
      5
      6
      string.index(substring[,start[,end]])

      # 参数说明:
      # - `substring`:指定要检索的子字符串。
      # - `start`:指定检索的起始位置(包括该字符),默认为0。
      # - `end`:指定检索的结束位置(不包括该字符),默认为字符串长度。
      1
      2
      str1 = "你好,世界!"
      print(str1.index("好"))

      输出结果为:

      1
      1

      可以看到,index()方法返回了字符串中子字符串 第一次出现的位置。

      注意:find()方法和 index()方法的区别在于,find()方法如果找不到子字符串,则返回-1,而 index()方法如果找不到子字符串,则抛出 ValueError异常。

      在Python中,还提供了 rfind()方法和 rindex()方法,它们的功能与 find()方法和 index()方法类似,但是是从字符串的末尾开始检索。

    4. startwith()方法:判断字符串是否以指定的子字符串开头,如果以指定的子字符串开头,则返回True,否则返回False。语法格式如下:

      1
      2
      3
      4
      5
      6
      string.startswith(substring[,start[,end]])

      # 参数说明:
      # - `substring`:指定要检索的子字符串。
      # - `start`:指定检索的起始位置(包括该字符),默认为0。
      # - `end`:指定检索的结束位置(不包括该字符),默认为字符串长度。
      1
      2
      str1 = "你好,世界!"
      print(str1.startswith("你好"))

      输出结果为:

      1
      True

      可以看到,startswith()方法返回了一个布尔值,用于判断字符串 str1是否以子字符串 你好开头。

    5. endswith()方法:判断字符串是否以指定的子字符串结尾,如果以指定的子字符串结尾,则返回True,否则返回False。语法格式如下:

      1
      2
      3
      4
      5
      6
      string.endswith(substring[,start[,end]])

      # 参数说明:
      # - `substring`:指定要检索的子字符串。
      # - `start`:指定检索的起始位置(包括该字符),默认为0。
      # - `end`:指定检索的结束位置(不包括该字符),默认为字符串长度。
      1
      2
      str1 = "你好,世界!"
      print(str1.endswith("!"))

      输出结果为:

      1
      True

      可以看到,endswith()方法返回了一个布尔值,用于判断字符串 str1是否以子字符串 结尾。

  6. 字母大小写转换

    • upper()方法:将字符串中的所有字母转换为大写字母,并返回新的字符串。语法格式如下:

      1
      string.upper()
      1
      2
      str1 = "Hello, World!"
      print(str1.upper())

      输出结果为:

      1
      HELLO, WORLD!

      可以看到,upper()方法将字符串 str1中的所有字母都转换为了大写字母。

    • lower()方法:将字符串中的所有字母转换为小写字母,并返回新的字符串。语法格式如下:

      1
      string.lower()
      1
      2
      str1 = "Hello, World!"
      print(str1.lower())

      输出结果为:

      1
      hello, world!

      可以看到,lower()方法将字符串 str1中的所有字母都转换为了小写字母。

  7. 去除空格和特殊字符

    • strip()方法:去除字符串中的空格,并返回新的字符串。
    • lstrip()方法:去除字符串中的左侧空格,并返回新的字符串。
    • rstrip()方法:去除字符串中的右侧空格,并返回新的字符串。
    1
    2
    3
    4
    5
    str_list = "    Nihao,Shijie    "
    print("|" + str_list + "|")
    print("|" + str_list.strip() + "|")
    print("|" + str_list.lstrip() + "|")
    print("|" + str_list.rstrip() + "|")

    输出结果为:

    1
    2
    3
    4
    |    Nihao,Shijie    |
    |Nihao,Shijie|
    |Nihao,Shijie |
    | Nihao,Shijie|
  8. 格式化字符串

    格式化字符串的意思是先制定一个模板,在这个模板中预留几个空位,然后根据空位的位置将数据填入空位中,最终得到一个完整的字符串。这些空位需要通过指定的符号标记(也称占位符),而这些符号还不会显示出来。在Python中,格式化字符串有以下两种方法。

    • 使用 %操作符

      语法格式如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      '%[-][+][0][m][n]格式化字符'%exp

      # 参数说明:
      # - [-]:可选参数,用于指定对齐方式。如果省略,则默认左对齐。如果添加`-`号,则表示右对齐。
      # - [+]:可选参数,用于指定是否显示符号。如果省略,则默认不显示符号。如果添加`+`号,则表示显示符号。
      # - [0]:可选参数,用于指定是否使用0填充。如果省略,则默认不使用0填充。如果添加`0`号,则表示使用0填充。
      # - [m]:可选参数,用于指定输出的最小宽度。如果省略,则默认根据数据长度输出。
      # - [n]:可选参数,用于指定输出的最大宽度。如果省略,则默认根据数据长度输出。
      # - 格式化字符:用于指定数据的输出格式。
      # - exp:用于指定要格式化的项。如果要指定的项有多个,需要通过元组的形式进行指定,但不能使用列表。
      1
      2
      3
      4
      5
      6
      7
      8
      name = "张三"
      age = 18
      text = ("李四", 28)
      template = "我是%s,我今年%d岁。\n"
      print(template % (name, age))
      print(template % text)
      print("我是%s,我今年%d岁。\n" % (name, age))
      print("我是%s,我今年%d岁\n" %text)

      输出结果为:

      1
      2
      3
      4
      5
      6
      7
      我是张三,我今年18岁。

      我是李四,我今年28岁。

      我是张三,我今年18岁。

      我是李四,我今年28岁

      ==这个格式化字符串的方法借鉴C语言,但二者并不完全一样==

      可以看到,%s表示字符串,%d表示整数。在格式化字符串中,%号后面的项需要按照格式化字符的顺序进行指定。如果要指定的项有多个,需要通过元组的形式进行指定,但不能使用列表。

    • 使用 format()方法

      语法格式如下:

      1
      2
      3
      4
      5
      string.format(args)

      # 参数说明:
      # - string:用于指定模板字符串。
      # - args:用于指定要格式化的项。如果要指定的项有多个,需要通过逗号进行分隔。

      下面介绍如何创建模板:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      {[index][:[[fill]align][width][.precision][type]]}
      也就是
      {[参数序号]:[填充][对齐][宽度][.精度][类型]}

      # 参数说明:
      # - index:可选参数,用于指定要格式化的项的索引。如果省略,则默认按照顺序进行格式化。
      # - fill:可选参数,用于指定填充字符。如果省略,则默认使用空格填充。
      # - align:可选参数,用于指定对齐方式。如果省略,则默认左对齐。如果添加`-`号,则表示右对齐。如果添加`0`号,则表示使用0填充。
      # - width:可选参数,用于指定输出的宽度。如果省略,则默认根据数据长度输出。
      # - precision:可选参数,用于指定输出的精度。如果省略,则默认根据数据类型输出。
      # - type:可选参数,用于指定数据的输出格式。如果省略,则默认根据数据类型输出。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      name = "张三"
      age = 18
      text = ("李四", 28)
      template = "我是{:s},我今年{:d}岁。\n"
      print(template.format(name, age))
      print(template.format(*text))
      print("我是{},我今年{}岁。\n".format(name, age))
      print("我是{},我今年{}岁。\n".format(*text)) #传入元组参数,也可以是列表
      print("我是{0[0]},我今年{0[1]}岁。\n".format(text)) #传入元组参数,也可以是列表
      #{0}表示两个中括号都传入text,然后根据索引选择元组中元素

      输出结果为:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      我是张三,我今年18岁。

      我是李四,我今年28岁。

      我是张三,我今年18岁。

      我是李四,我今年28岁。

      我是李四,我今年28岁。

下面是一些 format()方法中常用的格式化字符

格式字符 说明 示例 输出
d 十进制整数<br>用于整数格式化 "{:d}".format(42) 42
f 固定小数点浮点数<br>可指定小数位数 "{:.2f}".format(3.1415) 3.14
s 字符串<br>默认字符串格式 "{:s}".format("hello") hello
x 十六进制小写<br>整数转十六进制(小写字母) "{:x}".format(255) ff
X 十六进制大写<br>整数转十六进制(大写字母) "{:X}".format(255) FF
e 科学计数法小写<br>浮点数科学记数法(小写e) "{:.2e}".format(1234.5) 1.23e+03
% 百分比<br>自动乘以100并添加%符号 "{:.1%}".format(0.75) 75.0%
g 通用格式<br>自动选择 fe(更简洁) "{:g}".format(0.000123) 0.000123
> 右对齐<br>配合宽度使用 "{:>10}".format("hi") hi
< 左对齐<br>配合宽度使用 "{:<10}".format("hi") hi
^ 居中对齐<br>配合宽度使用 "{:^10}".format("hi") hi

第七章 Python中使用正则表达式

可以在这个网站里面练习正则表达式

正则表达式语法

正则表达式是一种用于匹配字符串的模式。它由字符和特殊字符组成,用于描述字符串的格式。正则表达式使用 re 模块进行匹配。

  1. 行定位符

    • ^:匹配字符串的开头。
    • $:匹配字符串的结尾。
    1
    2
    3
    ^tm    # 匹配以tm开头的字符串
    tm$ # 匹配以tm结尾的字符串
    tm # 匹配含有tm的字符串
  2. 元字符

代码 说明
. 匹配任意字符,除了换行符
\w 匹配字母或数字或下划线或汉字
\W 匹配非字母或数字或下划线或汉字
\s 匹配空白字符
\S 匹配非空白字符
\D 匹配非数字字符
\d 匹配数字
\b 匹配单词的开始或结束
\B 匹配非单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
  1. 重复
限定符 说明 举例
* 匹配前面的字符0次或多次 go*gle匹配从ggle到`goo……gle
+ 匹配前面的字符1次或多次 go+gle匹配从gogle到`goo……gle
? 匹配前面的字符0次或1次 go?gle匹配goglegoogle
{n} 匹配前面的字符n次 go{2}gle只匹配google
{n,} 匹配前面的字符n次或更多 go{2,}gle匹配从googlegoo……gle
{n,m} 匹配前面的字符n次到m次 go{2,4}gle匹配从googlegoooogle
  1. 字符类

    想要查找某些特定字符集合很简单,只需要在方括号[]内列出所有需要查找的字符即可。

    1
    2
    3
    [abc]         # 匹配a、b、c中的任意一个字符
    [a-z] # 匹配a-z之间的任意字符
    [a-zA-z0-9] # 匹配a-z、A-Z、0-9之间的任意字符
  2. 排除字符

    在方括号[]内添加一个^号,表示排除。

    1
    2
    [^abc]        # 匹配除了a、b、c之外的任意字符
    [^a-z] # 匹配除了a-z之间的任意字符
  3. 选择字符

    使用选择字符|,可以匹配多个字符。

    1
    a|b|c         # 匹配a、b、c中的任意一个字符
  4. 转义字符

    在正则表达式中,一些特殊字符有特殊含义,如 .*+?^$[]{}()| 等。如果这些字符需要匹配,则需要使用转义字符进行转义。

  5. 分组

    使用圆括号()可以将多个字符组合成一个分组。

    1
    (Desk|lap)top  # 匹配Desktop或laptop
  6. 在Python中使用正则表达式

    在Python中使用正则表达式时,是将其作为模式字符串使用的。例如:

    1
    2
    3
    '[^a-z]'

    '\byou\b'

    由于模式字符串中可能包括大量的特殊字符和反斜杠,所以需要写为原生自字符串,即在字符串开头加上r

    1
    2
    3
    r'[^a-z]'

    r'\byou\b'

使用re模块实现正则表达式操作

首先需要引入re模块:

1
import re
  1. 匹配字符串

    re.match()方法用于匹配字符串的开始,如果字符串满足模式,则返回相应的匹配对象,否则返回None。其语法格式如下:

    1
    2
    3
    4
    5
    6
    re.match(pattern, string, [flags])

    # 参数说明如下:
    pattern: 表示模式字符串,由要匹配的正则表达式转换而来
    string: 表示要匹配的字符串
    flags: 匹配标志,可选,用于控制匹配方式,,如是否区分字母大小写等。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import re
    print("根据身份证号来判断出生日期是不是1月1日")

    personID1 = "88888820021122000X"
    personID2 = "888888200201010000"

    regex = r"\d{6}\d{4}0101\d{4}|\d{6}\d{4}0101\d{3}(X|x)"

    match1 = re.match(regex, personID1)
    match2 = re.match(regex, personID2)

    print(match1)
    print(match2)

    if match1 == None:
    print(personID1 + "生日不是1月1日")
    else:
    print(personID1 + "生日是1月1日")
    if match2 == None:
    print(personID2 + "生日不是1月1日")
    else:
    print(personID2 + "生日是1月1日")

    输出结果为;

    1
    2
    3
    4
    None
    <re.Match object; span=(0, 18), match='888888200201010000'>
    88888820021122000X生日不是1月1日
    888888200201010000生日是1月1日

    匹配成功,返回匹配对象,否则返回None。

    re.search()方法用于匹配字符串的任意位置,如果字符串满足模式,则返回相应的匹配对象,否则返回None。其语法格式如下:

    1
    2
    3
    4
    5
    6
    re.search(pattern, string, [flags])

    # 参数说明如下:
    pattern: 表示模式字符串,由要匹配的正则表达式转换而来
    string: 表示要匹配的字符串
    flags: 匹配标志,可选,用于控制匹配方式,,如是否区分字母大小写等。

    re.search()方法与re.match()方法都是一次查找,找到后返回一个match对象,找不到返回none。不同是re.match()方法从头找,re.search()方法从任何位置找。

    re.findall()方法用于查找字符串中所有匹配的子串,并返回一个列表。其语法格式如下:

    1
    2
    3
    4
    5
    6
    re.findall(pattern, string, [flags])

    # 参数说明如下:
    pattern: 表示模式字符串,由要匹配的正则表达式转换而来
    string: 表示要匹配的字符串
    flags: 匹配标志,可选,用于控制匹配方式,,如是否区分字母大小写等。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import re
    IP = '''
    192.168.1.1
    255.255.255.0
    0.0.0.0
    3.3.3.3
    256.1.1.1
    1.1.1.1.1
    '''
    regex = r'(\b(((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?))\b)'
    match = re.findall(regex, IP)
    print(match)

    输出结果为:

    1
    [('192.168.1.1', '192.168.1.1', '1.', '1', '1'), ('255.255.255.0', '255.255.255.0', '255.', '255', '0'), ('0.0.0.0', '0.0.0.0', '0.', '0', '0'), ('3.3.3.3', '3.3.3.3', '3.', '3', '3'), ('1.1.1.1', '1.1.1.1', '1.', '1', '1')]
  2. 替换字符串

    re.sub()方法用于替换字符串中的匹配项,并返回替换后的字符串。其语法格式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    re.sub(pattern, repl, string, [count], [flags])

    # 参数说明如下:
    pattern: 表示模式字符串,由要匹配的正则表达式转换而来
    repl: 表示替换字符串,用于替换匹配项
    string: 表示要匹配的字符串
    count: 可选,指定替换次数,默认替换所有匹配项
    flags: 匹配标志,可选,用于控制匹配方式,,如是否区分字母大小写等。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import re
    IP = '''
    192.168.1.1
    255.255.255.0
    0.0.0.0
    3.3.3.3
    256.1.1.1
    1.1.1.1.1
    '''
    regex = r'(\b(((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?))\b)'
    match = re.sub(regex,'0.0.0.0',IP)
    print(match)

    输出结果为:

    1
    2
    3
    4
    5
    6
    0.0.0.0
    0.0.0.0
    0.0.0.0
    0.0.0.0
    256.1.1.1
    0.0.0.0.1
  3. 使用正则表达式分割字符串

    re.split()方法用于根据正则表达式模式将字符串分割成多个子串,并返回一个列表。其语法格式如下:

    1
    2
    3
    4
    5
    6
    7
    re.split(pattern, string, [maxsplit], [flags])

    # 参数说明如下:
    pattern: 表示模式字符串,由要匹配的正则表达式转换而来
    string: 表示要匹配的字符串
    maxsplit: 可选,指定最大分割次数,默认分割所有匹配项
    flags: 匹配标志,可选,用于控制匹配方式,,如是否区分字母大小写等。

第八章 函数

函数的创建和调用

  1. 创建一个函数

    创建函数也叫定义函数,可以理解为创建一个具有特定功能的函数,函数名后加括号括起来,括号里面可以添加参数。使用def关键字实现,语法格式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def 函数名(参数表):
    """注释内容,可选"""
    [函数体]

    # 参数说明
    函数名:函数名,函数名必须使用字母、数字、下划线组成,不能以数字开头。
    参数表:可选,函数的参数列表,多个参数用逗号隔开。
    注释内容:说明该函数的功能
    函数体:函数体,函数的实现内容,即函数被调用后需要执行的代码。如果函数有返回值,可以使用return语句返回结果。
  2. 调用一个函数

    调用函数也叫执行函数,使用函数名加括号括起来,括号里面可以添加参数。如果函数有返回值,可以使用变量接收返回值。语法格式如下:

    1
    函数名(参数表)

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def hello_world():
    print("你好,世界!")
    def plus(x1,x2):
    '''计算x1+x2的值'''
    return x1+x2

    print("Hello World")
    a = 260
    b = 260
    c = plus(a,b)
    hello_world()
    print(c)

    输出结果为:

    1
    2
    3
    Hello World!
    你好,世界!
    520

参数传递

  1. 了解形式参数和实际参数

    在使用函数时,经常会用到形式参数和实际参数。二者都叫参数,但形式参数是函数定义时定义的参数,实际参数是在调用函数时传入的参数。

    根据实际参数的不同,可以将实际参数的值传递给形式参数,或将实际参数的引用传递给形式参数。其中,当实际参数为不可变对象时,进行的是值传递,当实际参数为可变对象时,进行的是引用传递。

    • 值传递:形参是实参的拷贝,改变形参的值并不会影响外部实参的值。
    • 引用传递:形参相当于是实参的“别名”,改变形式参数的值,实际参数的值也会一同改变。
  2. 位置参数

    位置参数是指函数调用时,指定的实际参数的数量、顺序与形式参数的数量、顺序必须一致,否则会报错

      TypeError: can't multiply sequence by non-int of type 'str'
    

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def bmi_compute(person_name, height, weight):
    bmi = weight / (height * height)
    print(f"{person_name}的身高为{height},体重为{weight},BMI为{bmi}")
    if bmi < 18.5:
    print("您的体重过轻")
    elif bmi < 24.9:
    print("正常范围,注意保持")
    elif bmi < 29.9:
    print("您的体重过重")
    else:
    print("肥胖")

    bmi_compute("张三", 1.77, 75)
    bmi_compute("李四", 1.68, 48)

    输出结果为:

    1
    2
    3
    4
    张三的身高为1.77,体重为75,BMI为23.81
    正常范围,注意保持
    李四的身高为1.68,体重为48,BMI为17.45
    您的体重过轻
  3. 关键字参数

    关键字参数是指使用形式参数的名字来确定输入的参数值。通过该方式指定实际参数时,不再需要与形式参数的顺序一致,只要将参数名写对即可。例如:

    1
    2
    bmi_compute(person_name="张三", height=1.77, weight=75)
    bmi_compute(weight=48, person_name="李四", height=1.68)
  4. 默认参数

    默认参数是指在定义函数时,为形式参数指定默认值,当调用函数时,如果实际参数没有指定该形式参数,则使用默认值。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def bmi_compute(person_name, height, weight=70):
    bmi = weight / (height * height)
    print(f"{person_name}的身高为{height},体重为{weight},BMI为{bmi}")
    if bmi < 18.5:
    print("您的体重过轻")
    elif bmi < 24.9:
    print("正常范围,注意保持")
    elif bmi < 29.9:
    print("您的体重过重")
    else:
    print("肥胖")

    这里默认体重weight参数为70,当调用函数时,如果实际参数没有指定weight参数,则使用默认值70。

    注意:默认参数必须指向不可变对象。

  5. 可变参数

    可变参数是指在定义函数时,为形式参数指定一个参数名,该参数名可以接收任意多个实际参数。主要有两种形式,一种是*args,另一种是**kwargs

    • *args:用于接收任意多个实际参数,将这些参数打包成一个元组。
    • **kwargs:用于接收任意多个关键字参数,将这些参数打包成一个字典。

    例如*args参数的用法如下:

    1
    2
    3
    4
    5
    6
    7
    8
    def plus(*args):
    sum = 0
    for i in args:
    sum += i
    return sum

    sum = plus(1,2,3,4,5,6,7,8,9)
    print(sum)

    这里的*args参数可以接收任意多个实际参数,函数内部将这些参数打包成一个元组。

    上面代码输出结果为45。

    如果想使用一个已经存在的列表作为函数的可变参数,可以在列表的名称前面加上*,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def plus(*args):
    sum = 0
    for i in args:
    sum += i
    return sum

    arr = [1,2,3,4,5,6,7,8,9]
    sum = plus(*arr)
    print(sum)

    这里的*arr表示将列表arr中的元素作为可变参数传递给函数plus()

    上面的代码输出结果还是45。

    **kwargs参数的用法如下:

    1
    2
    3
    4
    5
    def print_info(**kwargs):
    for key, value in kwargs.items():
    print(f"{key}: {value}")

    print_info(name="张三", age=18, sex="男")

    这里的**kwargs参数可以接收任意多个关键字参数,函数内部将这些参数打包成一个字典。

    上面代码输出结果为:

    1
    2
    3
    name: 张三
    age: 18
    sex: 男

    如果想使用一个已经存在的字典作为函数的关键字参数,可以在字典的名称前面加上**,例如:

    1
    2
    3
    4
    5
    6
    def print_info(**kwargs):
    for key, value in kwargs.items():
    print(f"{key}: {value}")

    info = {"name": "张三", "age": 18, "sex": "男"}
    print_info(**info)

    这里的**info表示将字典info中的键值对作为关键字参数传递给函数print_info()

    上面代码输出结果为:

    1
    2
    3
    name: 张三
    age: 18
    sex: 男

返回值

在Python中,可以在函数体内使用return语句为函数指定返回值。该返回值可以是任意类型,并且无论return语句后面是否还有其他代码,函数都会立即返回。

例如:

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
28
29
30
31
32
33
34
from pycparser.c_ast import Break

def fun_checkout(money):
'''
功能:计算商品合计金额并进行折扣处理
money:保存商品金额的列表
返回商品合计金额和折扣后的金额
'''
money_old = sum(money) # 计算合计金额
money_new = money_old
if 500 <= money_old <= 1000: # 满500享受9折优惠
money_new = f'{money_old*0.9:.2f}'
elif money_old <= 2000: # 满1000享受8折优惠
money_new = f'{money_old*0.8:.2f}'
elif money_old <= 3000: # 满2000享受7折优惠
money_new = f'{money_old*0.7:.2f}'
else: # 满3000享受6折优惠
money_new = f'{money_old*0.6:.2f}'

return money_old, money_new

#*************************调用函数****************************#

print("\n开始结算金额······\n")
list_money = [] # 定义保存商品金额的列表
while True:
inmoney = float(input("输入商品金额(输入0表示输入完成)\n>>>"))
if int(inmoney) == 0:
break
else:
list_money.append(inmoney) # 将金额添加到金额列表中

money = fun_checkout(list_money) # 调用函数
print("合计金额,", money[0], "应付金额:", money[1])

变量的作用域

  1. 局部变量

    局部变量是指在函数内部定义的变量,局部变量只在函数内部有效,函数执行完毕后,局部变量将自动销毁。例如:

    1
    2
    3
    4
    def fun():
    a = 10
    print(a)
    fun()
  2. 全局变量

    全局变量是指在函数外部定义的变量,全局变量在整个程序中都有效。例如:

    1
    2
    3
    4
    a = 10
    def fun():
    print(a)
    fun()

匿名函数

在Python中,匿名函数(也叫Lambda函数)是使用lambda关键字定义的函数,是指没有名字的函数,应用在需要一个函数但不想费神去命名这个函数的场合。通常情况下,这样的函数只使用一次。语法格式如下:

1
2
3
4
5
result = lambda [arg1, arg2, ...]: expression

参数说明
arg1, arg2, ...:参数列表,可以有多个参数,参数之间用逗号隔开。
expression:函数体.

使用lambda表达式时,参数可以有多个,用逗号隔开,但表达式只能有一个,即只能返回一个值,而且也不能出现其他非表达式语句(如for或者while)

例如计算圆的面积:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 常规代码
import math
def area(r):
result = math.pi * r * r
return result
r = 10
print(f"半径为{r}的圆面积为{area(r)}")

# 使用匿名函数
import math
r = 10
result = lambda r:math.pi * r * r
print(f"半径为{r}的圆面积为{result(r)}")

输出结果均为:

1
半径为10的圆面积为314.1592653589793

第九章 面向对象程序设计

可以在菜鸟教程上面看看关于这一章的内容

面向对象概述

面向对象(Object Oriented Programming,OOP)是一种程序设计范式,将数据(对象)与操作(方法)进行封装,并组织在一起。

面向对象的核心概念包括类(Class)、对象(Object)、属性(Attribute)和方法(Method)。

  1. 对象

    通常将对象划分为两个部分,即静态部分和动态部分。静态部分被称为“属性”,任何对象都具备自身属性,是客观存在的且不可忽略的;动态部分指的是对象的行为,即对象执行的动作。

    在Python中,一切都是对象,这说明Python天生就是面向对象的。

  2. 类是封装对象的属性和行为的载体,反过来说,具有相同属性和行为的一类实体被称为类。

  3. 面向对象程序设计的特点

    面向对象程序设计具有三大基本特征:封装、继承和多态。

    • 封装 (Encapsulation)

      封装是将数据和操作这些数据的方法组合在一个单元中(也就是类),并尽可能地隐藏对象的内部实现细节。通过访问控制(如 public、private、protected 关键字),只对外暴露要的接口供外部交互。

      封装的主要优点包括:

      • 提高代码安全性:通过隐藏内部实现细节,防止外部代码直接访问或修改对象的私有数据
      • 增强可维护性:当内部实现需要更改时,只要保持接口不变,就不会影响其他部分的代码
      • 简化复杂性:使用者只需关注如何使用接口,而不必了解内部工作机制
    • 继承 (Inheritance)

      继承允许我们基于现有类创建新类。新类(称为子类或派生类)会自动获得父类(或基类)的属性和方法,并且可以在其基础上增加新的功能或重写父类的方法。

      继承的优势:

      • 代码重用:避免重复编写相同代码
      • 代码维护性:当需要修改父类时,只需要在父类中进行修改,所有继承自它的子类都会自动更新
      • 建立类层次结构:有助于更好地组织和管理代码
      • 支持多态性:为实现多态提供了前提条件
    • 多态 (Polymorphism)

    • 多态指的是同一个接口可以有多种不同的实现方式。换句话说,相同的操作作用于不同的对象时,会产生不同的执行结果。在运行时,可以通过父类引用调用子类的具体实现。

      多态的好处:

      • 提高灵活性和可扩展性:能够编写适用于不同类型对象的通用代码
      • 降低耦合度:减少了各模块间的相互依赖
      • 增强可维护性:添加新类型时无需修改现有代码

这三个特征共同构成了面向对象编程的核心概念,帮助开发者构建更加模块化、可维护和可扩展的软件系统。

类的定义与使用

  1. 定义类

    类的定义可以使用class关键字,后面跟着类名和冒号。类名通常采用驼峰命名法,即每个单词的首字母大写。语法格式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class ClassName:
    '''类的帮助信息''' # 类文档字符串
    statement # 类体

    # 参数说明

    - ClassName:类名,采用驼峰命名法
    - '''类的帮助信息''':类文档字符串,用于描述类的功能和使用方法
    - statement:类体,包含类的属性和方法定义,如果没有想好,可以使用 pass 占位符代替

    示例:
    class Geese:
    '''模拟鹅的类'''
    pass
  2. 创建类的实例

    class定义完成后,就可以创建类的实例了。实例化类的语法格式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ClassName(param1, param2, ...)

    # 参数说明
    - ClassName:类名,用于创建实例的类名
    - param1, param2, ...:构造函数的参数,用于初始化实例的属性,可选

    示例:
    wildGoose = Geese()
    print(wildGoose)
  3. 创建__init__方法

    在创建完类后,通常会创建一个构造函数__init__()方法,用于初始化实例的属性。构造函数的参数会传递给__init__方法,并保存在实例的属性中。每次创建新的实例时,Python都会自动执行它。__init__()方法必须包含一个self参数,这是一个指向实例本身的引用,用于访问类中的属性和方法

    1
    2
    3
    4
    5
    6
    class Geese:
    '''模拟鹅的类'''
    def __init__(self):
    print('创建了一个鹅的实例')

    wildGoose = Geese()

    输出结果为:

    1
    创建了一个鹅的实例

    除了self参数外,__init__()方法也可以接受其他参数,用于初始化实例的属性。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    class Geese:
    '''模拟鹅的类'''
    def __init__(self, name, age):
    self.name = name
    self.age = age

    Lucy = Geese("Lucy", 22)
    print(f"Lucy's name is {Lucy.name}, and age is {Lucy.age}")

    输出结果为:

    1
    2
    Lucy's name is Lucy, and age is 22

    也可以这样:

    1
    2
    3
    4
    5
    6
    7
    class Geese:
    '''模拟鹅的类'''
    def __init__(self, name, age):
    print(name)
    print(age)

    Donald = Geese('Donald', 20)

    输出结果为;

    1
    2
    Donald
    20
  4. 创建类的成员并访问

    类的成员主要由实例方法和数据成员组成。在类中创建了类的成员后,可以通过类的实例进行访问。

    • 创建实例方法并访问

      1
      2
      3
      4
      5
      6
      7
      8
      def functionName(self, param1, param2, ...):
      block

      # 参数说明
      - functionName:用于指定方法名,一般小写字母开头;
      - self:必要参数,表示类的实例本身;
      - param1, param2, ...:方法参数,可选。
      - block:方法体,包含方法执行的代码。

      实例方法与函数的主要区别就是,函数是实现某个独立特定的功能,而实例方法是实现类的一个行为,是类的一部分。

      实例方法创建完成之后,可以通过类的实例名称和.运算符来调用实例方法。例如:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      class Geese:
      '''模拟鹅的类'''
      def __init__(self, name, age):
      self.name = name
      self.age = age
      print(name)
      print(age)
      def fly(self, state):
      print(state)

      Donald = Geese('Donald', 20)
      print(f"My name is {Donald.name},and my age is {Donald.age}")
      Donald.fly("I'm free!!!")

      输出结果为:

      1
      2
      3
      4
      Donald
      20
      My name is Donald,and my age is 20
      I'm free!!!
    • 创建数据成员并访问

      首先来看类属性

      类属性是指定义在类中,并且在函数体外的属性。类属性可以在类的所有实例之间共享值,可以通过类名称或者实例名访问。例如:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      class Geese:
      '''雁类'''
      neck = "脖子较长"
      wing = "振翅频率高"
      def __init__(self):
      print(Geese.neck)
      print(Geese.wing)

      geese = Geese()

      输出结果为:

      1
      2
      脖子较长
      振翅频率高

      在Python中除了可以通过类名称访问类属性,还可以动态地为类和对象添加或修改属性。例如:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      class Geese:
      '''雁类'''
      neck = "脖子较长"
      wing = "振翅频率高"
      num = 0
      def __init__(self):
      Geese.num += 1
      print(str(Geese.num))
      print(Geese.neck)
      print(Geese.wing)

      geese1 = Geese()

      Geese.weight = "不太重"
      Geese.wing = "HelloWorld"

      geese2 = Geese()
      print(geese2.weight)

      输出结果为:

      1
      2
      3
      4
      5
      6
      7
      1
      脖子较长
      振翅频率高
      2
      脖子较长
      HelloWorld
      不太重

      然后再看实例属性

      实例属性是指定义在类中,并且在函数体中的属性。实例属性只能通过实例对象访问,不能通过类对象访问。实例属性的值是针对每个实例对象而言的,每个实例对象都有自己的属性值。例如:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      class Geese:
      '''雁类'''
      def __init__(self):
      self.neck = "脖子较长"
      self.wing = "振翅频率高"
      print(self.neck)
      print(self.wing)

      geese = Geese()

      输出结果为:

      1
      2
      脖子较长
      振翅频率高

      实例属性可以通过实例对象访问,也可以动态地为实例对象添加或修改属性。例如:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      class Geese:
      '''雁类'''
      def __init__(self):
      self.neck = "脖子较长"
      print(self.neck)

      geese1 = Geese()
      geese2 = Geese()
      geese2.neck = "没有天鹅的脖子长"
      print("geese1的neck属性:", geese1.neck)
      print("geese2的neck属性:", geese2.neck)

      输出结果为:

      1
      2
      3
      4
      脖子较长
      脖子较长
      geese1的neck属性: 脖子较长
      geese2的neck属性: 没有天鹅的脖子长
  5. 访问限制

    为了保证类内部的某些属性和方法不被外部访问,Python提供了访问限制,可以在属性或者方法名称前面添加单下划线 (_xxx)、双下划线 (__xxx) 或首尾添加双下划线 (__xxx__) 来达到访问限制的目的。

    • _xxx: 以单下划线开头的表示 protected(保护)类型的成员,只允许类本身和子类访问。

      1
      2
      3
      4
      5
      6
      7
      class Swan:
      '''天鹅类'''
      _neck = "脖子较长" # 定义保护属性
      def __init__(self):
      print("__init__():", Swan._neck) # 在实例方法访问保护属性
      swan = Swan() # 创建实例对# 创建Swan实例
      print("直接访问", swan._neck) # 通过实例名访问保护属性

      输出结果为:

      1
      2
      __init__(): 脖子较长
      直接访问 脖子较长
    • __xxx: 以双下划线开头的表示 private(私有)类型的成员,只允许类本身访问。

    • __xxx__: 双下划线开头和结尾的表示特殊方法,一般是系统定义名字,如__init__()

属性

这里的属性(property)与之前的类属性和实例属性不同,之前介绍的属性将返回所存储的值,本节介绍的属性则是一种特殊的属性,访问时将计算它的值。此外,该属性还可以为属性添加安全保护机制。

  1. 创建用于计算的属性

    在Python中,可以通过@property装饰器将一个方法转换为属性,从而可以直接通过方法名来访问方法,而不需要再添加()。例如:

    1
    2
    3
    @property
    def methodName(self):
    block

    示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Swan:
    '''天鹅类'''
    __neck = "脖子较长"

    def __init__(self, x, y):
    self.x = x
    self.y = y
    print("__init__():", Swan.__neck)
    @property
    def fly(self):
    print(self.x*self.y)
    return "I'm free!!!"
    swan = Swan(10, 5)
    print(swan.fly)

    输出结果为:

    1
    2
    3
    __init__(): 脖子较长
    50
    I'm free!!!
  2. 为属性添加安全保护机制

    在Python中,默认情况下是可以在类体外修改类属性和实例属性的,虽然可以设置为私有属性来限制外部修改,但这样的话外部都访问不了。所以可以使用@prorperty来创建一个可读不可写的属性。

    示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class TVshow:
    def __init__(self,title):
    self.title = title
    @property
    def show(self):
    return self.title
    tvshow = TVshow("七宗罪") # 可读
    print(f"正在播放:《{tvshow.show}》")
    tvshow.show = "绿皮书" # 不可写,会报错
    print(f"正在播放:《{tvshow.show}》")

    输出结果为:

    1
    2
    3
    4
    5
    正在播放:《七宗罪》
    Traceback (most recent call last):
    File "tvshow.py", line 12, in <module>
    tvshow.show = "绿皮书" # 不可写,会报错
    AttributeError: can't set attribute

    除了设置为只读属性之外,还可以为属性设置拦截器,只允许指定约束的修改,例如:

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    class TVshow:
    """电视节目类,用于管理可播放的电影列表及当前播放状态"""
    file_list = ["肖申克的救赎", "绿皮书", "七宗罪"] # 可播放的电影列表

    def __init__(self,show):
    """初始化电视节目实例

    Args:
    show: 初始显示的节目名称
    """
    self.__show = show

    @property
    def show(self):
    """获取当前节目的显示信息

    Returns:
    str: 当前节目的显示文本
    """
    return self.__show

    @show.setter
    def show(self,title):
    """设置要播放的节目,根据是否在播放列表中显示不同信息

    Args:
    title: 要设置的节目标题
    """
    if title in self.file_list:
    self.__show = f"即将播放:《{title}》"
    else:
    self.__show = f"没有影片《{title}》!"

    tvshow = TVshow("七宗罪") # 可读
    print(tvshow.show)
    tvshow.show = "绿皮书" # 不可写,会报错
    print(tvshow.show)
    tvshow.show = "阿甘正传"
    print(tvshow.show)
    1
    2
    3
    4
    5
    6
    7

    输出结果为:

    ```text
    即将播放:《七宗罪》
    即将播放:《绿皮书》
    没有影片《阿甘正传》!

继承

继承是面向对象编程的一个重要概念,它允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。子类可以继承父类的所有属性和方法,并且可以在其基础上添加新的属性和方法,或者重写父类的方法。

  1. 继承的基本语法

    通过继承不仅可以实现代码复用,还可以通过继承来理顺类与类之间的关系。在Python中,可以在类定义时,在类名的右侧使用一对小括号将要继承的父类名称括起来,具体语法格式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    class SubClassName(BaseClassName):
    '''类的帮助信息'''

    Statement

    # 参数说明
    # BaseClassName:父类名称
    # SubClassName:子类名称

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class Fruit:
    color = "绿色"
    def harvest(self, color):
    print("水果是:" + color + "的")
    print("水果已经丰收……")
    print("水果原来是:" + Fruit.color + "的")

    class Apple(Fruit):
    color = "红色"
    def __init__(self):
    print("\n我是苹果")

    class Orange(Fruit):
    color = "橙色"
    def __init__(self):
    print("\n我是橙子")

    apple = Apple()
    apple.harvest(apple.color)
    orange = Orange()
    orange.harvest(orange.color)

    输出结果为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    我是苹果
    水果是:红色的
    水果已经丰收……
    水果原来是:绿色的

    我是橙子
    水果是:橙色的
    水果已经丰收……
    水果原来是:绿色的

    虽然AppleOrange类都没有定义harvest()方法,但是它们继承了Fruit类的harvest方法,所以可以调用,即子类可以访问父类的方法

  2. 方法重写

    如果父类中的某个方法不完全适用于子类时,可以在子类里面重写这个方法。例如,我们可以将Orange类继承自Fruitharvest方法重写:

    1
    2
    3
    4
    5
    6
    7
    8
    class Orange(Fruit):
    color = "橙色"
    def __init__(self):
    print("\n我是橙子")
    def harvest(self, color):
    print("这个橙子是:" + color + "的")
    print("橙子丰收了!")
    print("这个橙子原来是:" + color + "的")

    输出结果为:

    1
    2
    3
    4
    我是橙子
    这个橙子是:橙色的
    橙子丰收了!
    这个橙子原来是:橙色的
  3. 子类调用父类的__init__()方法

    在面向对象编程中,子类继承了父类的属性和方法,如果子类需要在实例化时执行父类的初始化操作,就需要调用父类的构造函数。在Python中,使用super()函数来调用父类的构造函数。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Parent:
    def __init__(self, name):
    self.name = name
    print("Parent class constructor called")

    class Child(Parent):
    def __init__(self, name, age):
    super().__init__(name)
    self.age = age
    print("Child class constructor called")

    child = Child("Alice", 12)
    print(child.name)
    print(child.age)

    输出结果为:

    1
    2
    3
    4
    Parent class constructor called
    Child class constructor called
    Alice
    12

第十章 模块

模块概述

模块 (Models),是Python中组织代码的一种方式。模块可以包含函数、类、变量和语句等,用于实现特定的功能。模块的主要作用是将代码组织成逻辑上的单元,方便代码的管理和维护。

模块的文件名就是模块的名称,文件名的后缀是.py。例如,math.py就是一个模块,random.py也是一个模块。

自定义模块

自定义模块由两个作用:

  • 规范代码,让代码更易于阅读;
  • 方便其他程序使用已经编写好的代码,提高开发效率吧;
  1. 创建模块

    要创建一个模块,只需要在一个.py文件中编写Python代码即可。但设置的模块名不能是Python自带的标准模块名称。例如,math.py就是一个标准模块,不能将自己的模块命名为math.py

    例如,我们可以创建一个名为my_module.py的模块,在其中编写自己的代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # my_module.py

    def bmi_calc(person, weight, height):
    '''计算BMI指数'''
    print(f"{person} 的身高为 {height} m, 体重为 {weight} kg")
    bmi = weight / (height ** 2)
    print(f"{person} 的BMI指数为 {bmi}。")

    def hello(person):
    '''打招呼'''
    print("Welcome " + person + " !")
    print("Hello World!")
  2. 使用impport语句导入模块

    要在其他Python程序中使用自定义模块,需要使用import语句导入模块。例如,要导入my_module.py模块,只需要在程序中添加以下代码:

    1
    2
    3
    import my_module as mm
    # as mm 是为了避免与其他模块中的函数名冲突而给模块起一个别名
    # import语句也可以一次导入多个模块,中间使用逗号隔开

    导入模块后,就可以使用模块中定义的函数、类、变量和语句了。例如,要调用bmi_calc()函数,只需要添加以下代码:

    1
    mm.bmi_calc("张三", 100, 1.00)

    输出结果为:

    1
    2
    张三 的身高为 1.00 m, 体重为 100 kg
    张三 的BMI指数为 100.0。
  3. 使用from...import...语句导入模块

    除了使用import语句导入整个模块外,还可以使用from...import...语句导入模块中的特定函数、类、变量或语句。例如,要导入my_module.py模块中的bmi_calc()函数,只需要添加以下代码:

    1
    2
    from my_module import bmi_calc
    # 如果想导入多个如变量、函数、类的话,可以使用逗号隔开

    导入后,就可以直接调用bmi_calc()函数,而不需要使用模块名作为前缀。例如:

    1
    bmi_calc("张三", 100, 1.00)

    输出结果为:

    1
    2
    张三 的身高为 1.00 m, 体重为 100 kg
    张三 的BMI指数为 100.0。

    导入多个模块的多个内容时可能会出现重名现象,Python会以后导入的内容覆盖掉前一个导入的同名内容。这时就得使用import...语句了。