2025python学习笔记Part1

2025 Python语言基础入门学习笔记
部署运行你感兴趣的模型镜像

一.Python语言基础入门

第一章

01.初识Python

  • Python的起源:

    • 1989年,为了打发圣诞节假期,Gudio van Rossum吉多·范罗苏姆(龟叔)决心开发一个新的解释程序(Python维形)
    • 1991年,第一个Python解释器诞生
    • Python这个名字来自龟叔所挚爱的电视剧Monty Python’s Flying Circus
  • Python适用范围:

    • IT从业者:自动化脚本(运维开发、测试开发等)

    • 普通白领:自动化办公

    • 后端开发:WEB应用程序

    • 科学家:基于Python完成数据计算(生物、化学、物理)

    • 人工智能/机器学习:基于Python开发Al程序
    • 大数据开发:基于Python完成大数据任务开发(Spark、Flink)

02.什么是编程语言

  • 以Python为例
    • 用于人类和计算机进行交流的一种语言,通过编写编程语言的代码,去指挥计算机工作。
它无法直接和计算机沟通,需要翻译工具(解释器或编译器)将代码翻译成二进制,从而实现和计算机的畅顺沟通

03.Python安装

想要使用Python语言编写程序,我们必须下载Python安装包并配置Python环境,Python目前最新版本是:3.13.3(发布于2025年4月8日)

  • 安装Python开发环境

    • 第一步:打开网址:Welcome to Python.org

      • image-20250426224524748
    • 第二步:点击“Downloads”

      • image-20250426224717192
    • 第三步:进入后,点击“Download Python 3.13.3”

      • image-20250426224915286
    • 第四步:下载好后,点击Python安装包

      image-20250426230743199

    • 第五步:点击“Customize installation”,并且勾选“Add python.exe to PATH”

      • image-20250426231437936
    • 第六步:默认是全选的,点击“Next”

      • image-20250426231811572
    • 第七步:点击”Browse“,选择你想要放的位置

      • image-20250426232220065
    • 第八步:然后点击”Inatall“,开始安装

    • 第九步:安装成功后,会出现”Setup was successful“,然后点击”Disable path length limit“关闭路径长度的限制,最后点击close就行了

      • image-20250426232728867
    • 第十步:验证Python是否安装成功,同时按下”win+r“键,然后输入”cmd“,在命令行中输入”python“,如果出现如下情况,则证明安装成功。

      • image-20250426233804143

04.第一个Python程序——”Hello world“

  • 同时按下”win+r“键,然后输入”cmd“,在命令行中输入”python“,出现下面这个界面

    • image-20250426233804143
  • 然后接着输入“print(“Hello World”)”,然后按下回车,命令行便会打印“Hello World”,如下

    • image-20250427100745238
    需要注意的点:
    引号和括号必须要是英文的,不能是中文的,否则会报错,如下image-20250427101648826

05.Python解释器

基本原理:计算机只认识二进制,即0和1
  • 计算机并不认识Python代码,但是Python有解释器程序。安装Python环境就是在安装Python解释器程序,如下图:

Python解释器原理

  • Python解释器就两个功能:
    • 1.翻译代码
    • 2.提交给计算机运行
  • Python解释器在哪里
    • 存放在:<Python安装目录>/Python.exe
      • image-20250427105723307
    • 我们在CMD(命令提示符)程序内,执行的python,就是上图的python.exe程序
那么问题来了,当我们在命令行中输入完一行代码后,按下回车,程序就直接运行了,有什么办法可以同时运行多行代码呢?
  • 思路实现
    • 我们可以将代码,写入一个以”.py”结尾的文件中,使用python命令去运行它。
    • 如,在Windows系统的D盘,我们新建一个名为:test.py的文件,并通过记事本程序打开它,输入如下内容:
      • image-20250427111012796
    • 在“命令提示符”程序内,使用python命令,运行它,如图:
      • image-20250427111240013

06.Pycharm开发工具的安装

Python程序的开发有许多种方式,一般我们常见的有:

  • Python解释器环境内,执行单行代码

  • 使用Python解释器程序,执行Python代码文件

  • 使用第三方IDE(集成开发工具),如PyCharm软件,开发Python程序

安装步骤

  • 第一步:打开网址:https://www.jetbrains.com/zh-cn/pycharm/
  • 第二步:点击“下载”
    • image-20250427113121918
  • 第三步:选择社区版,点击“下载”
    • image-20250427120915908
  • 第四步:点击Pycharm安装包
  • 第五步:点击“下一步”
    • image-20250427114534189
  • 第六步:先选择安装路径,再点击下一步
    • image-20250427114746659
  • 第七步:选择如下按钮,然后点击下一步
    • image-20250427120007116
  • 第八步:点击“安装”
    • image-20250427120110507
  • 第九步:等待安装完成
    • image-20250427120319690
  • 第十步:点击“完成”
    • image-20250427120355280
  • 第十一步:点击安装好后的Pycharm
  • 第十二步:点击下一个
    • image-20250427124106775
  • 第十三步:勾选条款,然后点击“继续”
    • image-20250427124203761
  • 第十四步:点击”新建项目“
    • image-20250427124557698
  • 第十五步:按照下图操作,然后点击创建
    • image-20250427125059775
  • 第十六步:得到下图
    • image-20250427125451542
  • 第十七步:新建文件,鼠标右键点击”1“,创建Python文件“test.py”
    • image-20250427125631156
  • 第十八步:在”test.py“文件中写入”print(“Hello world”)“,然后点击红框处的绿色三角形,就会在底部的终端中显示输出结果
    • image-20250427125921746

07.Pycharm开发工具的使用

  • 如何修改主题
    • Pycharm的默认主题是黑色

    • 第一步:点击右上角齿轮按钮,找到”主题“并点击

      image-20250427151732082
    • 第二步:选择主题,有5个常用的主题可以选择,也可以选择获取更多主题

      image-20250427151854537
  • 修改默认字体和大小
    • 第一步:点击右上角齿轮按钮,找到”设置“并点击

      image-20250427152229815
    • 第二步:按照下面的步骤设置字体和字体大小

      • image-20250427152702211
    • 第三步:设置快捷键改变字体大小,点击设置中的”按键映射“,然后在右边的搜索框中输入”字体“,接着搜索,出现下面的结果

      • image-20250427153412410
    • 第四步:先点击上图中的”减少字体大小“,再点击”添加鼠标快捷方式“,如下图

      • image-20250427153633014
    • 第五步:出现下图后,同时点击”Ctrl+鼠标滚轮下滑“

      • image-20250427153808367
    • 第六步:出现下图后,就说明设置成功了,然后点击确定

      • image-20250427153915672
    • 第七步:按照”设置减小字体大小“的方法,设置”增大字体大小“的快捷键,如下

      • image-20250427154109768
    • 第八步:都设置完毕后,记住一定要点击“应用”

      • image-20250427154227141
  • 装一些好用的插件
    因为在安装最新版本的Pycharm时已经捆绑选择了中文插件,所以就不需要再次安装中文插件了!!!!
    • 安装翻译插件 ----------- 碰到不懂的英文,可以快速了解意思
      • 第一步:进入设置界面
      • 第二步:按照下图操作
        • image-20250427172918994
      • 第三步:安装好后,重启Pycharm
      • 第四步:用鼠标选中要翻译的单词,然后单击右键,点击”翻译“,出现下图
        • image-20250427173459066
  • 常用快捷键
    • ctrl + alt + s:打开软件设置

    • ctrl + alt + l:一键整理代码

    • ctrl + d:复制当前行代码

    • shift + alt + 上\下:将当前行代码上移或下移

    • crtl + shift + f10:运行当前代码文件

    • shift + f6:重命名文件

      如果遇到shift+f6快捷键不行的,可以在依次点击:设置>插件,然后在插件中搜索”Imefix“,然后下载对应的插件即可image-20250427181812618

    • ctrl + a:全选

    • ctrl + c\v\x:复制、粘贴、剪切

    • ctrl + z:撤回

    • ctrl + f:搜索

第二章

01.数据类型

Python中常用的数据类型有六种:数字(Number)、字符串(String)、列表(List)、元组(Tuple)、集合(Set)、字典(Dictionary)。其中数字类型又包括:整数(Int)、浮点数(float)、复数(complex)、布尔(bool),具体如下图:

9种常用Python数据类型

  • 1.整数
    整数是正数或负数,没有小数点的整数,例如:
    age = 23
    high = 176
    

    这里,age 和 high 都是整数。你可以对整数执行各种数学运算,例如:加(+)、减(-)、乘(*)、除(/)、地板除(//)、取模(%)、指数(**),详细的用法会在“运算符小节”讲到

  • 2.浮点数(小数)
    浮点数是有小数点的数字,例如:
    pi = 3.14159
    gravity = 9.81
    

    浮点数也可以像整数一样用于计算

  • 3.复数
    复数有一个实部和虚部,用’j’表示,例如:
    complex_number = 3 + 4j
    
  • 4.布尔
    布尔表示真值,例如:
    is_xiaogudu_gudu = True
    is_xiaogudu_ugly = False
    
    True和False在代码中起到决策的重要作用
  • 5.字符串(文本)
    字符串(string),又称文本,是由任意数量的字符如中文、英文、各类符号、数字等组成。所以叫做字符的串,如:“小孤独”,“1314”,“!@#$%^&”
    字符串是字符序列,用单引号或双引号括起来,例如:
    # 单行字符串
    name = "xiaogudu"
    message = 'Hello, how are you?'
    
    # 多行字符串,使用三引号
    long_text = """这是
    一个多行
    字符串字面量。"""
    

    ​ 字符串有很多方法,例如:len()方法用来计算字符串的长度,upper()方法用来将字符串中的所有小写字母转换为大写字母,并返回转换后的新字符串,等等…之后会详细学习

  • 6.列表
    列表是有序的、可变的序列,用方括号表示,例如:
    friends = ["伊地知虹夏", "喜多郁代", "山田凉"]
    numbers = [1, 2, 3, 4, 5]
    
    列表是多功能的,允许各种操作:
    friends.append("广井菊里")# 变成['伊地知虹夏', '喜多郁代', '山田凉', '广井菊里']
    friends.remove("喜多郁代")     # ['伊地知虹夏', '山田凉', '广井菊里']
    print(friends[0])        # 通过索引访问:伊地知虹夏
    print(friends[-1])       # 最后一个项目:广井菊里
    print(friends[1:3])      # 切片:['山田凉', '广井菊里']
    

    列表的具体方法之后再详细解释

  • 7.元组
    元组是有序的、不可变的序列,用圆括号表示,例如:
    tuple_one = (10, 20, 30)
    tuple_two = (255, 122, 128)
    
    元组类似于列表,但创建后不能修改:
    tuple_one = (10, 20, 30)
    print(tuple_one[0])  # 通过索引访问:10
    tuple_one[0] = 6   # 这将引发错误
    

    元组的具体方法之后再详细解释

  • 8.集合
    集合是无序的唯一元素集合,用花括号表示,例如:
    friends = {"伊地知虹夏", "喜多郁代", "山田凉"}
    numbers = {1, 2, 3, 4, 5}
    
    集合非常适合去除重复项和集合运算
    friends = {"伊地知虹夏", "喜多郁代", "山田凉"}
    friends.add("广井菊里")
    friends.remove("喜多郁代")
    print("山田凉" in friends)  # 检查成员资格:True
    
    set1 = {1, 2, 3}
    set2 = {3, 4, 5}
    print(set1.union(set2))        # 并集:{1, 2, 3, 4, 5}
    print(set1.intersection(set2)) # 交集:{3}
    

    集合的具体方法之后再详细解释

  • 9.字典
    字典存储键值对,用花括号表示,例如:
    person = {
    "name": "小孤独",
    "age": 16,
    "country": "Japan"
    }
    
    字典对于结构化数据非常有用:
    person = {
    "name": "小孤独",
    "age": 16,
    "country": "Japan"
    }
    
    print(person["name"])   # 通过键访问:小孤独
    person["job"] = "Band guitarist"  # 添加新的键值对
    del person["age"]       # 删除键值对
    print(person.keys())    # 获取所有键
    print(person.values())  # 获取所有值
    

    字典的具体方法之后再详细解释

02.数据类型的转换

有时候需要将数据从一种类型转换为另一种类型。Python为此提供了内置函数:
  • 转换为整数int()
    • 函数:int(x)
    • 适用场景:将字符串、浮点数、布尔值等转换为整数
    • 注意:非数字字符串或非整型浮点字符串会报错(如 int("3.14")int(5.0))
      int("123")     # 123(字符串转整数)
      int(3.14)      # 3(浮点数转整数,截断小数,会丢失精度)
      int(True)      # 1(布尔值转整数)
      int("1010", 2) # 10(二进制字符串转十进制)
      
  • 转换为浮点数float()
    • 函数:float(x)
    • 适用场景:将字符串、整数、布尔值等转换为浮点数
    • 函数:float(x)
      float("3.14")       # 3.14(字符串转浮点)
      float(5)            # 5.0(整数转浮点)
      float(False)        # 0.0(布尔值转浮点)
      
  • 转换为字符串str()
    • 函数:str(x)
    • 适用场景:任何类型的数据都可以转换成字符串
    • 注意:对复杂结构(如列表)直接转换可能不符合预期,需使用 json.dumps() 或自定义格式化
      str(100)         # "100"(整数转字符串)
      str(3.14)        # "3.14"(浮点转字符串)
      str([1, 2, 3])   # "[1, 2, 3]"(列表转字符串)
      
  • 转换为布尔值 bool()
    • 函数:bool(x)
    • 规则

      • False:空值(0, "", [], {}, None 等)。
      • True:其他非空对象。
      print(bool(0))          # False
      print(bool(""))         # False(空字符串)
      print(bool([]))         # False(空列表)
      print(bool({}))         # False(空字典)
      print(bool(set()))      # False(空集合)
      print(bool(None))       # False
      print(bool("Hello"))    # True
      
  • 转换为列表 list()
    • 函数:list(x)
    • 适用场景:将元组、集合、字符串、字典(仅保留键)等转换为列表
      print(list((1, 2, 3)))    # [1, 2, 3](元组转列表)
      print(list({"1",2,"a"}))  # (集合转列表),输出顺序可能为 ['1', 2, 'a'] 或其他,集合具有无序性
      print(list("abc"))        # ['a', 'b', 'c'](字符串转列表)
      print(list({"a": 1}) )    # ['a'](字典转键列表)
      
  • 转换为元组 tuple()
    • 函数:tuple(x)
    • 适用场景:将列表、集合、字符串等转换为不可变的元组
      print(tuple([1, 2, 3])) # (1, 2, 3) (列表转元组)
      print(tuple({1,2,3}))   # (1, 2, 3) (集合转元组)
      print(tuple("abc"))     # ('a', 'b', 'c') (字符串转元组)
      
  • 转换为集合 set()
    • 函数:set(x)
    • 适用场景:去重或转换字符串、列表、元组等为集合
      print(set([1, 2, 2, 3]))   # {1, 2, 3}(去重,列表转集合)
      print(set("hello"))        # {'h', 'e', 'l', 'o'} (字符串转集合)
      print(set((1, 2, 3)))      # {'c', 'b', 'a'} (元组转集合)
      
  • 转换为字典dict()
    • 函数:dict(x)
    • 适用场景:将键值对结构(如列表嵌套元组)转换为字典
      print(dict([(1, 'a'), (2, 'b')]))   # {1: 'a', 2: 'b'} ,列表嵌套元组转字典
      print(dict(x=1, y=2))  # {'x': 1, 'y': 2}
      

03.字面量

  • 什么是字面量?
    • 字面量就是在代码中,被写下来固定的值,Python的9种数据类型就是字面量,例如:数字字面量,整数字面量,复数字面量,字典字面量。

    • 举个例子:

      print("Hello, World!")
      

      在这行代码中,“Hello, World!” 就是一个字面量。它是一个固定的值,我们告诉Python去显示它。

  • Python字面量的类型
    • 整数字面量

      这些是正的或负的整数,没有小数点。

      age = 23
      high = 176
      

      这里,23和176是整数字面量。它们表示精确的、整数值

    • 浮点数字面量

      这些是有小数点的数字。

      pi = 3.14159
      gravity = 9.81
      

      3.14159和9.81是浮点数字面量。它们允许我们处理更精确的数值。

    • 复数字面量

      这些数字有实部和虚部。

      complex_number = 3 + 4j
      

      这里,3 + 4j是一个复数字面量,3是实部,4是虚部。它在高级数学计算中使用。

    • 布尔字面量

      布尔字面量表示真值。

      is_xiaogudu_gudu = True
      is_xiaogudu_ugly = False
      

      True和False是布尔字面量,它们 在代码中用于条件判断。

    • 字符串字面量

      字符串是字符序列,用单引号(‘’)或双引号(“”)括起来。

      # 单行字符串
      name = "xiaogudu"
      message = 'Hello, how are you?'
      
      # 多行字符串,使用三引号
      long_text = """这是
      一个多行
      字符串字面量。"""
      
    • 列表字面量

      列表是有序的项的集合(可以更改)

      friends = ["伊地知虹夏", "喜多郁代", "山田凉"]
      numbers = [1, 2, 3, 4, 5]
      

      方括号[]内的项创建列表字面量。

    • 元组字面量

      元组类似于列表,但它们是不可变的(不能更改)。

      tuple_one = (10, 20, 30)
      tuple_two = (255, 122, 128)
      

      圆括号()内的项创建元组字面量。

    • 集合字面量

      集合是无序的唯一项的集合。

      friends = {"伊地知虹夏", "喜多郁代", "山田凉"}
      numbers = {1, 2, 3, 4, 5}
      

      大括号{}内的项(但没有键值对)创建集合字面量。

    • 字典字面量

      字典存储键值对。

      person = {"name": "xiaogudu", "age": 16, "city": "神奈川县"}
      

      大括号{}内的键值对创建字典字面量。

04.注释

  • 注释:在程序代码中对程序代码进行解释说明的文字
  • 注释的作用:
    • 注释不是程序,不能被执行,只是对程序代码进行解释说明,让别人可以看懂程序代码的作用,能够大大增强程序的可读性。
  • 注释的分类:
    • 单行注释:
      • #开头,#右边的所有文字当作说明,而不是真正要执行的程序,起辅助说明作用。

      • 单行注释一般用于对一行或一小部分代码进行解释

      • # 我是单行注释
        print("Hello World!!!")
        
        注意:#号和注释内容一般建议以一个空格隔开
    • 多行注释:
      • 以 ”一对三个双引号“ 引起来(“”“注释内容”“”)来解释说明一段代码的作用使用方法

      • 多行注释一般对:Python文件、类或方法进行解释

      • """
        	我是多行注释
        	我是多行注释
        	我是多行注释
        """
        print("Hello World!!!")
        print("Hello World!!!")
        

05.变量

  • 变量:在程序运行时,能储存计算结果或能表示值的抽象概念。简单来说变量就是在程序运行时,记录数据用的
  • 变量的定义格式:
    • 变量名称 = 变量的值
      • “变量名称”:每一个变量都有自己的名称,称之为:变量名,也就是变量本身

      • “=”:赋值,表示将等号右侧的值,赋予左侧的变量

      • “变量的值”:每一个变量都有自己存储的值(内容),称之为:变量值

  • 创建变量:
    • 基本赋值:
      age = 16
      name = "小孤独"
      hobby = "喜欢弹吉他"
      

      在这些例子中:

      ​ age 是一个变量,存储着年龄(整数)
      ​ name 也是一个变量,存储着名字(字符串)
      ​ hobby 也是一个变量,存储着爱好(也是字符串)

    • 多重赋值:

      Python 允许我们高效地在一行内给多个变量赋值

      age, name, hobby = 16, "小孤独", "喜欢弹吉他"
      print(age)   # 打印“16”
      print(name)  # 打印“小孤独”
      print(hobby) # 打印“喜欢弹吉他”
      

      这就像发牌一样 - 每个变量按顺序获得自己的值

  • 删除变量:

    在 Python 中,我们可以使用 del 关键字删除不再需要的变量

    name = "小孤独" #创建变量并赋值
    print(name)  # 输出“小孤独”
    del name     # 删除变量
    print(name)  # 这将引发一个错误,说明变量删除成功
    
  • 变量地址:

    Python 中的每个变量在计算机内存中都有一个唯一的地址,就像街道上的每座房子都有自己的地址一样。我们可以使用 id() 函数找出变量所在的位置:

    name = "小孤独"
    print("name 的内存地址:", id(name)) 
    #打印语句会输出“name 的内存地址: 3141631801696”
    

    上述的数字就是变量在计算机内存中的地址

  • 变量类型:

    Python 允许我们使用·type() 函数检查变量所持有的数据类型:

    age = 16
    name = "小孤独"
    print(type(age))  # 打印语句输出“<class 'int'>”
    print(type(name)) # 打印语句输出“<class 'str'>”
    

    这告诉我们 age 是一个整数(int),而 name 是一个字符串(str)

  • 变量的类型转换:

    有时,我们需要改变变量的类型。这个过程称为类型转换。

    age = 16
    print(type(age))  # 打印语句输出“<class 'int'>”
    age_str = str(age) # 将变量从数字类型转换成字符串类型
    print(type(age_str)) # 打印语句输出“<class 'str'>”
    
  • 变量命名约定:
    • 变量以字母或下划线开头

    • 变量可以包含字母、数字和下划线

    • 变量区分大小写

    • 变量不能是 Python 关键字

    • 好名字:

      age = 16
      name = "小孤独"
      hobby = "喜欢弹吉他"
      
    • 坏名字:

      2film = "电影"  # 不能以数字开头
      my-age = 20    # 不允许使用连字符
      
  • 全局变量和局部变量:
    • 全局变量:

      全局变量就像派对的主持人 ,它们在整个程序中都是已知的:

      global_var = "我无处不在!"
      
      def use_global():
          print(global_var) # 打印“我无处不在!”
      
      use_global()  # 这可以正常工作
      print(global_var)   # 打印“我无处不在!”
      
    • 局部变量:

      在函数内部创建的变量称为局部变量。它们就像只存在于该函数中的秘密:

      def party_planner():
          local_var = "我只在这个函数中存在"
          print(local_var)
      
      party_planner()
      print(local_var)  # 这将引发一个错误
      
  • 常量:

    常量是值不应该改变的变量。在 Python 中,我们使用全部大写名称来表示常量:

    PI = 3.14159
    MAX_GUESTS = 50
    
    print("Pi 总是", PI)
    print("我们不能有超过", MAX_GUESTS, "个宾客")
    

06.标识符

  • 什么是标识符
    • 在Python程序中,我们可以给很多东西起名字,比如:
      变量的名字,方法的名字,类的名字,等等
    • 这些名字,我们把它统一的称之为标识符,用来做内容的标识。
      所以,标识符就是用户在编程的时候所使用的一系列名字,用于给变量、类、方法等命名
  • 标识符命名规则(需要强制遵守)
    Python中,标识符命名的规则主要有3类:
    • 内容限定
      • 只允许出现:**英文、中文、数字、下划线(_)**这四类元素
      • 注意:1.不推荐使用中文;2.数字不能在开头
    • 大小写敏感
      • 字母的大小写是完全能够分开的,例如:

        name = "小孤独1"
        Name = "小孤独2"
        print(name)   # 输出:小孤独1
        print(Name)   # 输出:小孤独2
        
    • 不可使用关键字
      • 关键字的定义:

        以下是 Python 3.10 及更高版本的关键字列表(共 35 个):

        False    None    True     and      as       assert   async
        await    break   class    continue def      del      elif
        else     except  finally  for      from     global   if
        import   in      is       lambda   nonlocal not      or
        pass     raise   return   try      while    with     yield
        match    case    
        

        用途分类:

        逻辑值:True, False, None
        
        逻辑运算:and, or, not
        
        流程控制:if, elif, else, for, while, break, continue
        
        函数与类:def, return, class, lambda, pass, raise, yield
        
        异常处理:try, except, finally, with, assert
        
        作用域:global, nonlocal
        
        模块操作:import, from, as
        
        异步编程:async, await
        
  • 标识符命名规范(建议遵守)
    不同的标识符有不同的命名规范,但是现在只学到了变量,所以只讲变量的命名规范:
    变量的命名规范:
    • 见名知意
      • 明了:尽量做到,看到名字,就知道是什么意思
      • 简洁:尽量在确保“明了”的前提下,减少名字的长度
    • 下划线命名法
      • 多个单词组合变量名,要使用下划线做分隔

        first_number = 1
        student_name = "小孤独"
        
    • 英文字母全小写
      • 变量中的英文字母应该全部小写

07.运算符

  • 算数运算符
    # 加法
    print(5 + 3)  # 输出:8
    
    # 减法
    print(10 - 4)  # 输出:6
    
    # 乘法
    print(3 * 4)  # 输出:12
    
    # 除法
    print(20 / 5)  # 输出:4.0
    
    # 整除/地板除(向下取整到最近的整数)
    print(17 // 3)  # 输出:5
    
    # 取模(除法的余数)
    print(17 % 3)  # 输出:2
    
    # 幂运算
    print(2 ** 3)  # 输出:8
    
  • 比较运算符

    这些运算符就像编程比赛中的评委——它们比较值并返回TrueFalse

    # 等于
    print(5 == 5)  # 输出:True
    
    # 不等于
    print(5 != 3)  # 输出:True
    
    # 大于
    print(7 > 3)   # 输出:True
    
    # 小于
    print(2 < 8)   # 输出:True
    
    # 大于或等于
    print(5 >= 5)  # 输出:True
    
    # 小于或等于
    print(3 <= 1)  # 输出:False
    
  • 逻辑运算符
    # and 运算符
    print(True and True)   # 输出:True
    print(True and False)  # 输出:False
    
    # or 运算符
    print(True or False)   # 输出:True
    print(False or False)  # 输出:False
    
    # not 运算符
    print(not True)        # 输出:False
    print(not False)       # 输出:True
    
  • 赋值运算符

    这些运算符就像Python中的搬运工——它们为变量赋值

    # 简单赋值运算符
    x = 5
    print(x)  # 输出:5
    
    # 复合赋值运算符(下面7个都是)
    # 加法赋值运算符
    x += 3    # 等同于 x = x + 3
    print(x)  # 输出:8
    
    # 减法赋值运算符
    x -= 2    # 等同于 x = x - 2
    print(x)  # 输出:6
    
    # 乘法赋值运算符
    x *= 2    # 等同于 x = x * 2
    print(x)  # 输出:12
    
    # 除法赋值运算符
    x /= 3    # 等同于 x = x / 3
    print(x)  # 输出:4.0
    
    # 取模赋值运算符
    x %= 3    # 等同于 x = x % 3
    print(x)  # 输出:1.0
    
    # 幂赋值运算符
    x **= 3   # 等同于 x = x ** 3 = x^3
    print(x)  # 输出:1.0
    
    # 取整除赋值运算符
    x //= 2   # 等同于 x = x // 2 
    print(x)  # 输出:0.0
    
  • 位运算符
    # 1.按位与(&)
    # 功能:两个二进制数的对应位都为 1 时,结果位才为 1,否则为 0
    a = 5   # 二进制 0000 0101(补码)
    b = 3   # 二进制 0000 0011(补码)
    result = a & b
    print(result)  # 输出 1 (二进制 0000 0001)
    
    # 2.按位或(|)
    # 两个二进制数的对应位有一个为 1,结果位就为 1
    a = 5   # 0000 0101(补码)
    b = 3   # 0000 0011(补码)
    result = a | b
    print(result)  # 输出 7 (0000 0111)
    
    # 3.按位异或(^)
    # 功能:两个二进制数的对应位不同时,结果位为 1,否则为 0
    a = 5   # 0000 0101(补码)
    b = 3   # 0000 0011(补码)
    result = a ^ b
    print(result)  # 输出 6 (0000 0110)
    
    # 4.按位取反(~)
    # 功能:将二进制数的每一位取反(0 变 1,1 变 0)
    a = 5   # 二进制 0000 0101(补码)
    result = ~a
    print(result)  # 输出 -6(即二进制补码 1111 1010)
    
    # 5.左移(<<)
    # 功能:将二进制数的所有位向左移动指定位数,右侧补 0
    a = 5   # 0000 0101(补码)
    result = a << 1  # 左移 1 位
    print(result)    # 输出 10 (0000 1010)
    
    # 6.右移(>>)
    # 功能:将二进制数的所有位向右移动指定位数,左侧补符号位(正数补 0,负数补 1)
    a = 5   # 0000 0101(补码)
    result = a >> 1  # 右移 1 位
    print(result)    # 输出 2 (0000 0010)
    
    b = -8 # 1111 1000(补码)
    result = b >> 2  # 右移 2 位(负数保留符号)
    print(result)    # 输出 -2
    
  • 身份运算符

    身份运算符用于比较两个对象的内存位置

    # is 运算符
    x = [1, 2, 3]
    y = [1, 2, 3]
    z = x
    
    print(x is z)  # 输出:True
    print(x is y)  # 输出:False
    print(x == y)  # 输出:True
    
    # is not 运算符
    print(x is not y)  # 输出:True
    
  • 成员运算符

    这些运算符就像俱乐部门口的保镖——它们检查一个值是否是序列的成员

    # in 运算符
    fruits = ['apple', 'banana', 'cherry']
    print('banana' in fruits)  # 输出:True
    
    # not in 运算符
    print('mango' not in fruits)  # 输出:True
    
  • 运算符的优先级
    优先级运算符描述
    1()括号
    2**幂运算
    3+x, -x, ~x一元加,一元减,按位非
    4*, /, //, %乘法,除法,整除,取模
    5+, -加法,减法
    6<<, >>按位左移,按位右移
    7&按位与
    8^按位异或
    9|按位或
    10<, >, <=, >=, ==, !=, is, is not, in, not in比较运算符,身份运算符,成员运算符
    11not逻辑运算符非
    12and逻辑运算符与
    13or逻辑运算符或
    14=, +=, -=, *=, /=, %=, **=, //=赋值运算符

08.字符串扩展

  • 字符串的三种定义方式
    • 字符串在Python中有3种定义形式

      • 1.单引号定义法:name = ‘小孤独’

      • 2.双引号定义法:name = "小孤独 "

      • 3.三引号定义法:name = " " "小孤独 " " "

        需要注意的是,三引号定义法,和多行注释的写法一样,同样支持换行操作。使用变量接收它,它就是字符串;不使用变量接收它,就可以作为多行注释使用。

    • 如何定义本身就包含引号的字符串

      • 1.单引号定义法,可以内含双引号

        # 在字符串内包含双引号
        name = '"小孤独"'
        print(name)   # 输出:"小孤独"
        
      • 2.双引号定义法,可以内含单引号

        # 在字符串内包含单引号
        name = "'小孤独'"
        print(name)   # 输出:'小孤独'
        
      • 3.可以使用转移字符(\)来将引号解除效用,变成普通字符串

        # 使用转义字符(\)解除引号的效用
        name = " \"小孤独\" "
        print(name)   # 输出:"小孤独"
        name = ' \'小孤独\' '
        print(name)   # 输出:'小孤独'
        
  • 字符串拼接
    • 如果我们有两个字符串(文本)字面量,可以将其拼接成一个字符串,通过+号即可完成,如:

      # 字符串字面量之间的拼接
      print("小孤独" + "学Python") # 输出:小孤独学Python
      
    • 不过一般,单纯的2个字符串字面量进行拼接显得很呆,一般,字面量和变量或变量和变量之间会使用拼接,如:

      # 字符串字面量和字符串变量的拼接
      name = "小孤独"
      study = "学Python"
      print("我是:"+name +",我要:"+ study) # 输出:我是:小孤独,我要:学Python
      
    • 字符串无法和非字符串类型直接进行拼接

  • 字符串格式化
    • 1.使用 % 运算符

      • %s 是一个字符串的占位符,而 “World” 是替换它的值

        print("Hello, %s!" % "World")  # 输出:Hello, World!
        
      • 你可以使用多个占位符

        注意:多个变量占位,变量要用括号括起来,并按照占位的顺序填入

        name = "小孤独"
        age = 16
        print("My name is %s and I am %s years old." % (name, age))
        # 输出:My name is 小孤独 and I am 16 years old.
        
      • Python中支持非常多的数据类型占位,最常用的如下

        格式符号转化
        %s将内容转换成字符串,放入占位位置
        %d将内容转换成整数,放入占位位置
        %f将内容转换成浮点型,放入占位位置

        示例:

        name ="小孤独"
        age = 16
        height = 1.56
        message ="我是%s,我的年龄是:%d,我的身高是:%f米" %(name, age, height)
        print(message)
        # 输出:我是:小孤独,我的年龄是:16,我的身高是:1.560000米
        
    • 2.str.format() 方法

      • Python 2.6+ 引入的更灵活的格式化方法,使用 {} 作为占位符

      • 基本用法:

        print("Name: {}, Age: {}".format("小孤独", 16))          # 位置参数
        print("Name: {1}, Age: {0}".format(16, "小孤独"))        # 索引参数
        print("Name: {name}, Age: {age}".format(name="小孤独", age=16))  # 关键字参数
        
      • 格式控制:

        # 数字格式化
        print("PI: {:.2f}".format(3.14159))  # 输出:PI: 3.14(保留两位小数)
        print("Hex: {:x}".format(255))       # 输出:Hex: ff(十六进制)
        
        # 对齐与填充
        print("{:>10}".format("Hello"))      # 右对齐,宽度10 → '     Hello'
        print("{:<10}".format("Hello"))      # 左对齐,宽度10 → 'Hello     '
        print("{:*^10}".format("Hi"))        # 居中并用*填充 → '****Hi****'
        
        # 千位分隔符
        print("{:,}".format(1000000))        # 输出:1,000,000
        
      • 引用对象属性或元素:

        person = {"name": "小孤独", "age": 16}
        print("Name: {p[name]}, Age: {p[age]}".format(p=person))  # 输出:Name: 小孤独, Age: 16
        
    • 3.f-strings(格式化字符串字面量)

      • Python 3.6+ 引入,语法简洁高效,在字符串前加 fF,变量直接嵌入 {}

      • 基本用法:

        name = "小孤独"
        age = 16
        print(f"Name: {name}, Age: {age}")  # 输出:Name: 小孤独, Age: 16
        
      • 表达式和函数调用:

        name = "xiaogudu"
        age = 16
        # 直接计算表达式
        print(f"Next year's age: {age + 1}")  # 输出:Next year's age: 17
        
        # 调用方法或函数
        print(f"Name in uppercase: {name.upper()}")  # 输出:Name in uppercase: XIAOGUDU
        
      • 高级格式控制:

        pi = 3.14159
        print(f"PI: {pi:.2f}")               # 输出:PI: 3.14
        print(f"Hex: {255:x}")               # 输出:Hex: ff
        print(f"Aligned: {'text':>10}")      # 输出:Aligned:       text
        
      • 多行字符串:

        name = "小孤独"
        age = 16
        message = (
            f"Name: {name}\n"
            f"Age: {age}\n"
            f"Square of Age: {age ** 2}"
        )
        print(message)  
        # 输出:Name: 小孤独
        # Age: 16
        # Square of Age: 256
        
    • 4.模板字符串(string.Template

      • Python 标准库中的简单模板,通过 $ 占位符替换,适合用户可控的输入(避免安全风险)

        from string import Template
        t = Template("Name: $name, Age: $age")
        print(t.substitute(name="小孤独", age=16))  # 输出:Name: 小孤独, Age: 16
        
    • 5.总结对比:

      方法优点缺点适用场景
      % 格式化简单,兼容旧代码功能有限,易出错旧项目或简单替换
      str.format()功能强大,支持复杂格式语法稍冗长需要兼容 Python 2.6+
      f-strings简洁高效,支持表达式仅限 Python 3.6+现代 Python 代码首选
      string.Template安全,适合用户输入功能最少用户可控模板
  • 格式化的精度控制

    我们可以使用辅助符号m.n来控制数据的宽度和精度

    • m:控制宽度,要求是数字(很少使用),设置的宽度小于数字自身,不生效

    • n:控制小数点精度,要求是数字,会进行小数的四舍五入

      示例:

      • 1.%运算符

        num1 = 11
        num2 = 11.345
        num3 = 0.001234
        print("数字11宽度限制5,结果是:%5d" % num1)
        print("数字11.345宽度限制7,小数精度2,结果是:%7.2f" % num2)
        print("数字11.345不限制,小数精度2,结果是:%.2f" % num2)
        print("数字11.345不限制,小数精度3,结果是:%.3e" % num2)
        print("数字0.001234不限制,小数精度2,结果是:%.2g" % num3)  
        # 输出:
        # 数字11宽度限制5,结果是:   11  (数前面有3个空格,因为宽度限制为5)
        # 数字11.345宽度限制7,小数精度2,结果是:  11.35 (数前面有2个空格,保留两位小数)
        # 数字11.345不限制,小数精度2,结果是:11.35  (保留两位小数) 
        # 数字11.345不限制,小数精度3,结果是:1.135e+01  (科学计数法,保留三位小数)
        # 数字0.001234不限制,小数精度2,结果是:0.0012  (保留两位有效数字)
        
      • 2.str.format() 方法

        num1 = 11
        num2 = 11.345
        num3 = 0.001234
        num4 = 12345678.946
        print("数字11宽度限制5,结果是:{:5d}".format(num1))
        print("数字11.345宽度限制7,小数精度2,结果是:{:7.2f}".format(num2))
        print("数字11.345不限制,小数精度2,结果是:{:.2f}".format(num2))
        print("数字11.345不限制,小数精度3,结果是:{:.3e}".format(num2))
        print("数字0.001234不限制,小数精度2,结果是:{:.2g}".format(num3))
        # 输出:省略
        -------------------以下是%运算符没有的用法-----------------------
        
        print("数字12345678.946不限制,小数精度2,结果是:{:,.2f}".format(num4))
        print("数字11.345不限制,小数精度2,结果是:{:*>10.2f}".format(num2))
        print("数字0.001234不限制,小数精度2,结果是:{:.2%}".format(num3))
        #输出:
        # 数字12345678.946不限制,小数精度2,结果是:12,345,678.95 (千分位分隔符)
        # 数字11.345不限制,小数精度2,结果是:*****11.35  (右对齐,宽度10,填充*)
        # 数字0.001234不限制,小数精度2,结果是:0.12%     (百分比显示)
        
      • 3.f-strings(Python 3.6+)

      # 跟str.format() 方法 一样
      num1 = 11
      num2 = 11.345
      num3 = 0.001234
      num4 = 12345678.946
      print(f"数字11宽度限制5,结果是:{num1:5d}")
      print(f"数字11.345宽度限制7,小数精度2,结果是:{num2:7.2f}")
      print(f"数字11.345不限制,小数精度2,结果是:{num2:.2f}")
      print(f"数字11.345不限制,小数精度3,结果是:{num2:.3e}")
      print(f"数字0.001234不限制,小数精度2,结果是:{num3:.2g}")
      print(f"数字12345678.946不限制,小数精度2,结果是:{num4:,.2f}")
      print(f"数字11.345不限制,小数精度2,结果是:{num2:*>10.2f}")
      print(f"数字0.001234不限制,小数精度2,结果是:{num3:.2%}")
      # 输出:
      # 省略
      
      • 关键格式说明符

        • f:固定小数位数(如 .2f)。
        • e/E:科学计数法(小写/大写指数符号)。
        • g/G:自动选择 fe,控制有效数字(如 .3g)。
        • %:百分比格式(自动乘100并添加%)。
        • ,:千分位分隔符(如 {:,.2f})。
        • 对齐与填充<(左对齐)、>(右对齐)、^(居中),结合宽度和填充字符(如 :*>10.2f)。
  • 对表达式进行格式化
    • 表达式的定义

      • 一条具有明确执行结果的代码语句,例如:1+1、3*4、name = “小孤独”、age =16 这些都是表达式,因为有具体结果(变量的等号右侧为结果),结果是一个数字或者字符串。
    • 如何格式化表达式:

      print("1*1的结果是:%d" % (1*1))       # %运算符
      print("1*2的结果是:{}".format(1*2))  # str.format()
      print(f"2*3的结果是:{2*3}")          # f-strings
      print("字符串在Python中的类型名是:%s" % type("字符"))
      # 输出:
      # 1*1的结果是:1
      # 1*2的结果是:2.00
      # 2*3的结果是:6
      # 字符串在Python中的类型名是:<class 'str'>
      

09.数据输入

在Python中,我们使用input()语句,用来获取键盘输入:

  • 使用input()语句可以从键盘获取输入

  • 使用一个变量接收(存储)input语句获取的键盘输入数据即可
    示例:

    name = input("你是谁?")  # 输入:小孤独
    print(f"我是{name}")     # 输出:我是小孤独
    
    age = input("你多大了?")  # 16
    print(f"我{age}岁了,类型:{type(age)}") # 输出:我16岁了,类型:<class 'str'>
    

    从中可以发现:无论键盘输入什么类型的数据,获取到的数据永远都是字符串类型

第三章

01.判断语句(条件语句)

1.if语句

最简单形式

if 条件1:
    # 条件1为 True 时执行

示例:

age = 16
if age == 16:
    print (f"小孤独{age}岁了")  # 输出:小孤独16岁了

在这个例子中,如果 age 等于16,它将打印消息。如果不是,则什么也不会发生。

if语句的注意事项:

  • 判断条件的结果一定要是布尔类型
  • 不要忘记判断条件后的:冒号
  • 归属于if语句的代码块,需在前方填充4个空格缩进
2.if-else语句

如果想在条件不成立时也执行某些语句,这就需要用到else

if 条件1:
    # 条件1为 True 时执行
else:
    # 以上条件为 False 时执行

示例:

age = 16

if age >= 18:
    print("你可以驾驶汽车!")
else:
    print("抱歉,你太小不能驾驶汽车。")  # 输出:抱歉,你太小不能驾驶汽车。

这里,如果年龄是18岁或以上,它将打印 “你可以驾驶汽车!”。否则,它将打印另一条消息。

if-else语句的注意事项:

  • else不需要判断条件,当if的条件不满足时,else执行
  • else的代码块,同样要4个空格作为缩进
3.if-elif-else语句

当需要检查多个条件时, ‘elif’(‘else if’ 的缩写)就派上用场了

if 条件1:
    # 条件1为 True 时执行
elif 条件2:
    # 条件2为 True 时执行(可以有多个)
else:
    # 以上条件均为 False 时执行

示例:

score = 85

if score >= 90:
    print("A")
elif score >= 80:
    print("B")
elif score >= 70:
    print("C")
else:
    print("需要加油!")  # 输出:B

使用if-elif-else的注意事项:

  • elif可以写多个
  • 判断是互斥且有序的,上一个满足后面的就不会判断了
  • 可以在条件判断中,直接写input语句,节省代码量

02.判断语句的嵌套

判断语句的嵌套是指在一个条件判断(if/elif/else)的代码块中,再包含另一个完整的条件判断结构。这种写法常用于处理多层次的逻辑分支,如下:

  • 基础嵌套语法

    if 条件1:
        # 条件1成立时执行
        if 条件2:
            # 条件1和条件2均成立时执行
        else:
            # 条件1成立但条件2不成立时执行
    else:
        # 条件1不成立时执行
    

    示例:

    score = 85
    
    if score >= 60:
        print("及格")
        if score >= 80:
            print("优秀")
            if score >= 90:
                print("顶尖水平")
        else:
            print("普通水平")
    else:
        print("不及格")
        
    # 输出:
    # 及格
    # 优秀
    

第四章

循环语句

1.for循环

基本语法:

for 变量 in 可迭代对象:
    # 循环体代码
  • 用途:遍历序列(如列表、字符串、元组、字典、集合等)或任何可迭代对象。

  • 特点:明确知道循环次数或需要遍历每个元素时使用。

示例:

# 1.遍历列表
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
    print(fruit)    # 输出:苹果 香蕉 橙子

-------------------------------------------------------    
# 2.遍历字符串
for char in "Python":
    print(char)  # 逐个输出字符:P, y, t, h, o, n
    
-------------------------------------------------------
# 3.使用 range()
for i in range(5):      # 0到4(不包含5)
    print(i)            # 输出:0 1 2 3 4

for i in range(2, 6):   # 2到5
    print(i)            # 输出:2 3 4 5

for i in range(0, 10, 2):  # 步长为2:0, 2, 4, 6, 8
    print(i)               # 输出:0 2 4 6 8
    
---------------------------------------------------------  
#  4.遍历字典
student = {"name": "小明", "age": 18, "grade": "A"}
for key in student:
    print(key, ":", student[key])  # 输出键值对

# 直接遍历键值对:
for key, value in student.items():
    print(key, "->", value)
for循环的嵌套
  • 基本格式

    for 外层变量 in 外层可迭代对象:
        # 外层循环代码
        for 内层变量 in 内层可迭代对象:
            # 内层循环代码
    
  • 示例:

    # 九九乘法表
    for i in range(1,10):
        for j in range(1,i+1):
            print(f"{j} x {i} = {i*j}",end="\t")
        print()
    
range()语句
  • 基本语法

    • 语法1range(num)
      获取一个从0开始到num结束的数字序列(不含num本身)

      for i in range(5):      # 0到4(不包含5)
          print(i)            # 输出:0 1 2 3 4
      
    • 语法2range(num1, num2)
      获得一个从num1开始,到num2结束的数字序列(不含num2本身)

      for i in range(2, 6):   # 2到5
          print(i)            # 输出:2 3 4 5
      
    • 语法3:range(num1, num2, step)
      获得一个从num1开始,到num2结束的数字序列(不含num2本身)
      数字之间的步长,以step为准(step默认为1)

      for i in range(0, 10, 2):  # 步长为2:0, 2, 4, 6, 8
          print(i)               # 输出:0 2 4 6 8
      
for循环变量作用域
  • for 临时变量 in 待处理数据集:
    	循环满足条件时执行的代码
    

    回看for循环的语法,我们会发现,将从数据集(序列)中取出的数据赋值给临时变量。

    临时变量,在编程规范上,作用范围(作用域)只限定在for循环内部。
    但是如果在for循环外部访问临时变量

    • 实际上是可以访问到的

    • 在编程规范上,是不允许、不建议这么做的

    • 如需访问临时变量,可以预先在循环外定义它,例如:

      i = 0   # 先在循环外定义变量
      for i in range(5):
          print(i)
      print(i)
      
2.while循环

基本语法:

while 条件:
    # 循环体代码
  • 用途:当条件为 True 时重复执行代码块。
  • 特点:不确定循环次数,需根据条件动态判断。

示例:

# 1.基础计数器
count = 0
while count < 3:
    print(count)
    count += 1  # 输出:0 1 2
    
-------------------------------------------------------
# 2.用户输入控制
user_input = ""  # 初始化变量,用于存储用户输入
while user_input.lower() != "quit":  # 循环条件:当输入不是"quit"时继续循环
    user_input = input("输入内容(输入 'quit' 退出): ")  # 获取用户输入
    print("你输入了:", user_input)  # 打印输入内容(包括"quit")

while循环的注意事项:

  • 条件需提供布尔类型结果,True继续,False停止
  • 空格缩进不能忘
  • 请规划好循环终止条件,否则将无限循环
While循环的嵌套
  • 基本格式:

    # 外层循环
    while 外层条件:
        # 外层循环体代码
    
        # 内层循环
        while 内层条件:
            # 内层循环体代码
    

    执行流程

    1. 外层循环条件为 True 时,进入外层循环体。
    2. 执行外层循环代码后,进入内层循环。
    3. 内层循环会完整执行(直到内层条件为 False),然后返回到外层循环。
    4. 外层循环再次判断条件,重复上述过程。
  • 示例:

    # 九九乘法表
    i = 1  # 外层循环变量,控制行数(1到9)
    while i <= 9:  # 外层循环:处理每一行
        j = 1  # 内层循环变量,控制当前行的列数(1到i)
        while j <= i:  # 内层循环:生成当前行的每个乘法表达式
            print(f"{j}×{i}={i*j}", end="\t")  # 打印表达式,用制表符分隔
            j += 1  # 内层循环变量自增
        print()  # 换行(当前行结束)
        i += 1  # 外层循环变量自增
    
3.循环控制语句
break关键字
  • **作用:**立即终止循环

  • 示例:

    for i in range(1,10):
        语句1                  
        break  -----
        语句2       |     
    语句3 <----------        
    
    • 在循环内,遇到break就结束循环了
    • 所以,执行语句1后,会直接执行语句3
  • 应用场景:

    • 在循环中,搜索目标后提前退出
    • 防止无限循环
  • break在嵌套循环中的应用

    for i in range(1,10):
        语句1
        for j in range(1,100):
            语句2  -----
            break      |
            语句3       |
        语句4  <---------
    
    • break只会影响所在的循环,不会影响上层循环

    • 所以只有语句3是不会执行的

continue关键字
  • **作用:**中断本次循环,直接进入下一次循环

  • 示例:

    for i in range(1,10):  <---
        语句1                  |
        continue   ------------
        语句2
    
    • 在循环内,遇到continue就结束当次循环,进行下一次
    • 所以语句2是不会执行的
  • 应用场景:

    • 在循环中,因某些原因,临时结束本次循环
  • continue在嵌套循环中的应用

    for i in range(1,10):
        语句1
        for j in range(1,100): <----
            语句2                   |
            continue  --------------
            语句3
        语句4
    
    • continue只会影响所在的循环,不会影响上层循环
    • 所以只有语句3是不会执行的

第五章:数据容器

Python 中的数据容器是一种可以存储多个元素的数据类型,每一个元素可以是任意类型。

数据容器根据特点的不同,如:

  • 是否支持重复元素
  • 是否可以修改
  • 是否有序,等

常见的数据容器有 5 种:列表( list )、元组( tuple )、字符串( str )、集合( set )、字典( dict )

5.1 列表(List)

5.1.1 列表的定义

有序、可变(可以修改)的集合,元素可以是任意类型,允许重复

5.1.2 基本语法
# 字面量
[元素1,元素2,元素3,.......]

# 定义变量
变量名称 = [元素1,元素2,元素3,.......]

# 定义空列表
变量名称 = []
变量名称 = list()

# 定义嵌套列表
变量名称 = [[元素1],[元素2],[元素3]]
  • 列表内的 每一个数据 被称为 元素
    • 方括号 [] 作为标识
    • 列表内的每一个元素之间用 逗号, 隔开
5.1.3 列表的索引
  • 作用:访问列表中的 单个元素

  • 语法list[index]

  • 特点

    • 使用单个整数下标(支持正数从 0 开始,负数从 -1 开始)。
    • 返回的是元素本身(不是列表)。
    • 索引越界会抛出 IndexError
  • 列表中的每个元素都有索引,从 0 开始,依次递增,如下:

    friends = ["Alice", "Bob", "Tom", "David"]
    print(friends[0])  # "Alice"  第一个元素
    print(friends[2])  # "Tom"    第三个元素
    print(friends[3])  # "David"  第四个元素
    
  • 当然索引也可以是反向的,也就是从后向前,从-1 开始,依次递减,如下:

    friends = ["Alice", "Bob", "Tom", "David"]
    print(friends[-1])  # "David"  倒数第一个元素
    print(friends[-2])  # "Tom"    倒数第二个元素
    print(friends[-4])  # "Alice"  倒数第四个元素
    
  • 如果列表是嵌套的,同样也可以使用索引

    friends = [["Alice", "Bob"], ["Tom", "David"]]
    print(friends[0][1])   # "Bob"   第一个元素里的第二个元素
    print(friends[1][1])   # "David" 第二个元素里的第二个元素 
    
  • 注意事项
    • 要注意索引的取值范围,超出范围无法取出元素,并且会报错(索引越界会抛出 IndexError
5.1.4 列表的切片
  • 作用:获取列表中的 子序列(一段连续元素)

  • 语法list[start:stop:step]

  • 特点

    • 使用 start(起始索引)、stop(结束索引,不包含)、step(步长)三个参数。
    • 返回的是 新列表(原始列表的浅拷贝)。
    • 索引越界时 自动截断,不会报错。
    • 参数可省略:
      • start 默认为 0
      • stop 默认为列表末尾
      • step 默认为 1
  • 示例

    friends = ["Alice", "Bob", "Charlie", "David", "Eve"]
    print(friends[1:4])  # 从索引 1 开始,到索引 4(不包括)
    print(friends[:3])   # 从开始到索引 3(不包括)
    print(friends[2:])   # 从索引 2 到末尾
    print(friends[::2])  # 每隔一个项
    
    # 输出:
    # ['Bob', 'Charlie', 'David']
    # ['Alice', 'Bob', 'Charlie']
    # ['Charlie', 'David', 'Eve']
    # ['Alice', 'Charlie', 'Eve']
    
5.1.5 列表的常用操作(方法)

首先先了解一下,方法和函数的区别

在 Python 中,如果 将函数定义为 class(类)的成员,那么函数则被称为 方法,例如:

# 函数
def add(x,y):
    return x + y

# 方法
class Student:
    def add(self, x, y):
        return x + y

方法和函数的功能一样,有传入参数,有返回值,只是方法使用的格式不同

函数的使用: num = add(1,2)

方法的使用:student = Student()

num = student.add(1,2)

01.查找某元素的索引
  • 功能:查找指定元素在列表的索引,如果找不到就会报错 ValueError
  • 语法:列表.index(元素)

    index 就是列表对象(变量)内置的方法(函数)

  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    index = fruits.index("香蕉")
    print(index)   # 输出:1
    
    index = fruits.index("芒果")
    print(index) 
    # 输出:ValueError: '芒果' is not in list
    
    
02.插入元素
  • 功能:在指定的索引位置插入指定的元素
  • 语法:列表.insert(索引,元素)
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    
    fruits.insert(1,"芒果")
    print(fruits)
    # 输出:['苹果', '芒果', '香蕉', '橙子', '西瓜']
    
03.追加单个元素
  • 功能:将单个元素添加到列表末尾
  • 语法:列表.append(元素)
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    
    fruits.append("芒果")
    print(fruits)
    # 输出:['苹果', '香蕉', '橙子', '西瓜', '芒果']
    
04.追加多个元素
  • 功能:将其它数据容器内的内容取出,依次追加到列表末尾
  • 语法:列表.extend(其它数据容器)
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    foods = ["milk", "hamburger", "chocolate"] 
    
    fruits.extend(foods)
    print(fruits)
    # 输出:['苹果', '香蕉', '橙子', '西瓜', 'milk', 'hamburger', 'chocolate']
    
05.删除元素(通过索引)
  • 功能:删除列表中指定元素
  • 语法:
    1. del 列表 [索引] 修改原列表,无返回值
    2. 列表.pop(索引) 修改原列表,同时返回被删除的元素
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    del fruits[1:3]  # 切片
    print(fruits)  # ['苹果', '西瓜']
    
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    del fruits[1]
    print(fruits) # ['苹果', '橙子', '西瓜']
    
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    element = fruits.pop(1)
    print(fruits) # ['苹果', '橙子', '西瓜']
    print(element) # 香蕉
    
06.删除元素(通过元素内容)
  • 功能:删除列表中第一个匹配的指定值
  • 语法:列表.remove(值)
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "香蕉"]
    fruits.remove("香蕉")  # 只删除第一个"香蕉"
    print(fruits)    # 输出:['苹果', '橙子', '香蕉']
    
07.清空列表
  • 功能:删除整个列表
  • 语法:列表.clear()
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "香蕉"]
    fruits.clear()
    print(fruits)  # 输出:[]
    
08.修改元素
  • 功能:修改特定位置(索引)的元素值:
  • 语法:列表 [索引] = 值
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    
    # 修改索引为1的元素(第二个元素)
    fruits[1] = "芒果"  
    
    print(fruits)  
    # 输出:['苹果', '芒果', '橙子', '西瓜'] 
    
09.统计某个元素的数量
  • 功能:统计某元素在列表内的数量
  • 语法:列表.count(元素)
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜", "苹果", "香蕉", "橙子"]
    print(fruits.count("苹果")) # 输出:2
    
10.统计所有元素的数量
  • 功能:统计列表中一共有多少元素
  • 语法:len(列表)
  • 示例:
    fruits = ["苹果", "香蕉", "橙子", "西瓜"]
    print(len(fruits))  # 输出:4
    
11.总结
操作类型功能描述语法返回值
1查找索引返回元素首次出现的索引列表.index(元素)索引(int)
2插入元素在指定索引处插入元素列表.insert(索引, 元素)None
3追加单个元素在列表末尾添加单个元素列表.append(元素)None
4追加多个元素将可迭代对象元素逐个追加到列表列表.extend(可迭代对象)None
5按索引删除删除指定索引的元素del 列表[索引]None
6按索引删除删除并返回指定索引的元素列表.pop(索引)被删除的元素
7按值删除删除第一个匹配的指定值列表.remove(元素)None
8清空列表移除列表中的所有元素列表.clear()None
9统计单个元素数量统计此元素在列表中出现的次数列表.count(元素)次数(int)
10统计列表元素总和统计容器内有多少元素len(列表)长度(int)
11修改元素修改指定索引的元素值列表[索引] = 新值None
5.1.6 列表的遍历

遍历就是将容器内的元素依次取出,并处理。有两种遍历方式:for 循环和 while 循环

for 循环
  • 基本语法:

    for element in my_list:
      # 对每个元素执行操作
      print(element)
    
  • 详细说明:

    • 直接访问元素:不需要索引,直接访问列表中的每个元素
    • 自动迭代:Python 自动处理迭代过程,无需手动控制索引
    • 简洁安全:语法简洁,不易出现索引错误
  • 示例:

    # 基本遍历
    fruits = ["apple", "banana", "cherry"]
    for fruit in fruits:
      print(f"I like {fruit}s")
    
while 循环
  • 基本语法:

    index = 0
    while index < len(my_list):
      element = my_list[index]
      # 对元素执行操作
      print(element)
      index += 1  # 必须手动递增索引
    
  • 详细说明

    • 手动控制索引:需要初始化索引变量并手动递增
    • 更灵活的控制:可以在循环中任意改变索引值
    • 潜在风险:容易忘记递增索引导致无限循环
  • 示例:

    # 基本遍历
    fruits = ["apple", "banana", "cherry"]
    index = 0
    while index < len(fruits):
      print(f"Fruit #{index+1}: {fruits[index]}")
      index += 1
    
两种循环对比
特性for 循环while 循环
语法简洁性非常简洁相对冗长
索引控制自动管理手动管理
错误风险低(不易出错)高(可能越界或无限循环)
灵活性有限(顺序访问)高(任意顺序/跳跃)
性能通常更优稍低(需额外索引操作)
适用场景大多数情况特殊迭代需求

5.2 元组(Tuple)

为什么需要元组呢?

因为列表里的数据可以被修改,如果想要不被修改,就需要使用元组。

5.2.1 元组的定义

定义元组使用 小括号,且使用 逗号 隔开各个数据,数据可以是不同的数据类型

5.2.2 基本语法
# 定义元组字面量
(元素,元素,......,元素)
# 定义元组变量 
变量名称 = (元素,元素,......,元素)
# 定义空元组
变量名称 = ()        # 方式1
变量名称 = tuple()   # 方式2
  • 注意事项:
    # 定义3个元素的元组
    t1 = (1, "hello", True)
    
    # 定义1个元素的元组
    t2 = ('hello',)   # 注意,必须带有逗号,否则不是元组类型
    

    注意,必须带有逗号,否则不是元组类型

5.2.3元组的嵌套
# 定义一个嵌套元组
t1 = ((1,2,3),(4,5,6))
print(t1[0][0])  # 输出:1
5.2.4 元组的常用操作
index()
  • 作用:查找某个数据,如果数据存在返回对应的索引,否则报错
  • 示例:
    # 根据index(),查找特定元素的第一个匹配项
    t1 = (1, 2, "hello", 3, 4, "hello")
    print(t1.index('hello'))  # 输出:2
    
count()
  • 作用:统计某个数据在当前元组出现的次数
  • 示例:
    # 统计某个数据在元组内出现的次数
    t1 = (1, 2, "hello", 3, 4, "hello")
    print(t1.count("hello")) # 输出 :2
    
len()
  • 作用:统计元组内的元素个数
  • 示例:
    # 统计元组内的元素个数
    t1 = (1, 2, 3)
    print(len(t1)) # 输出:3
    
操作总结
方法作用
1index()查找某个数据,如果数据存在返回对应的索引,否则报错
2count()统计某个数据在当前元组出现的次数
3len(元组)统计元组内的元素个数
5.2.5 元组的遍历
for 循环
  • 基本语法:

    for element in my_tuple:
      # 对每个元素执行操作
      print(element)
    
  • 示例:

    t1 = (1, 2, "hello", 3, 4, "hello")
    for element in t1:
    print(f"元组的元素有:{element}")
    
while 循环
  • 基本语法:

    index = 0
    while index < len(my_tuple):
      element = my_tuple[index]
      # 对元素执行操作
      print(element)
      index += 1  # 必须手动递增索引
    
  • 示例:

    t1 = (1, 2, "hello", 3, 4, "hello")
    
    index = 0
    while index < len(t1):
    print(f"元组的元素有:{t1[index]}")
    #至关重要
    index += 1
    
5.2.6 特殊情况:元组不能修改,但是元组里的列表可以修改
  • 直接修改元组会报错

    t1 = (1, 2, "hello", 3, 4, "hello")
    
    t1[0] = "hello"
    print(t1)
    # 报错输出:
    #    t1[0] = "hello"
    #    ~~^^^
    # TypeError: 'tuple' object does not support item assignment
    
  • 修改元组里嵌套的列表不会报错

    t1 = ([1, 2], "hello", 3, 4, "hello")
    
    t1[0][1] = "hello"
    print(t1)  # 输出:([1, 'hello'], 'hello', 3, 4, 'hello')
    

5.3 字符串(Str)

5.3.1 字符串的定义

字符串是字符的容器,一个字符串可以存放任意数量的字符。字符串和元组一样都不能被修改

5.3.2 字符串的索引
  • 通过索引取值
  • 示例:
    name = "xiaogudu"
    print(name[0])  # 输出:x
    print(name[-1]) # 输出:u
    
5.3.3 字符串的遍历
for 循环
  • 示例:
    my_str = "apple and banana"
    for i in my_str:
      print(i)
    
while 循环
  • 示例:
    my_str = "apple and banana"
    index = 0
    while index < len(my_str):
      print(my_str[index])
      index += 1
    
5.3.4 字符串的常用操作
index()方法
  • 作用:查找特定字符串的索引值
  • 语法:字符串.index(字符串)
  • 示例:
    my_str = "apple and banana"
    print(my_str.index("and")) # 输出:6
    
replace()方法
  • 作用:将字符串内的全部:字符串 1,替换成字符串 2
  • 语法:字符串.replace(字符串 1, 字符串 2)
  • 注意:不是修改字符串本身,而是得到了一个新的字符串
  • 示例:
    my_str = "apple and banana"
    new_my_str = my_str.replace("a","HELLO")
    print(new_my_str) 
    # 输出:HELLOpple HELLOnd bHELLOnHELLOnHELLO
    
split()方法
  • 作用:按照指定的 分隔符字符串,将字符串划分为多个字符串,并存入列表对象中
  • 语法:字符串.split(分隔符字符串)
  • 注意:不是修改字符串本身,而是得到了一个新的字符串
  • 示例:
    my_str = "apple and banana"
    new_my_str = my_str.split("a")
    print(new_my_str) 
    # 输出:['', 'pple ', 'nd b', 'n', 'n', '']
    
strip()方法
  • 作用:字符串的规整操作
  • 语法:
    • 字符串.strip() 【去除前后空格和换行符】
    • 字符串.strip(字符串) 【去除前后指定字符串】
  • 示例:
    # 去除前后空格
    my_str1 = " apple and banana "
    print(my_str.strip()) # 输出:apple and banana
    
    # 去除前后指定字符串
    my_str2 = "123apple and banana321"
    print(my_str.strip("123")) # 输出:apple and banana
    

    **注意:传入的是“123”其实就是:”1”和”2 " 和”3“都会移除,是按照单个字符 **

count()方法
  • 作用:统计字符串中某字符串的出现次
  • 语法:字符串.count(指定字符串)
  • 示例:
    my_str = "apple and banana"
    count = my_str.count("a")
    print(f"字符串a出现的次数:{count}") # 输出:5
    
len()方法
  • 作用:统计字符串的长度
  • 语法:len(字符串)
  • 示例:
    my_str = "apple and banana"
    num = len(my_str)
    print(f"字符串的长度是:{num}") # 输出:16
    
方法总结
编号方法语法说明
1index()字符串[index](字符串)查找给定字符的第一个匹配项的下标
2replace()字符串.replace(字符串1, 字符串2)将字符串内的全部字符串 1,替换为字符串 2
不会修改原字符串,而是得到一个新的
3split()字符串.split(字符串)按照给定字符串,对字符串进行分隔
不会修改原字符串,而是得到一个新的列表
4strip()字符串.strip()
字符串.strip(字符串)
移除首尾的空格和换行符或指定字符串
5count()字符串.count(字符串)统计字符串内某字符串的出现次数
6len()len(字符串)统计字符串的字符个数
5.3.5 字符串的大小比较

在程序中,字符串所用的所有字符如:

  • 大小写英文单词
  • 数字
  • 特殊符号(!、\、I、@、#、空格等)

都有其对应的 ASCII 码表值。每一个字符都能对应上一个:数字的码值。字符串进行比较就是基于数字的码值大小进行比较的

常见的如下:

范围字符类型十进制值
0-31控制字符0-31
48-57数字 0-948-57
65-90大写字母 A-Z65-90
97-122小写字母 a-z97-122

ASCII 值顺序: 数字 < 大写字母 < 小写字母

字符串是按位比较,也就是一位位进行对比,只要有一位大,那么整体就大。

  • 示例 1: 逐个字符比较

    # 比较过程示例
    s1 = "apple"
    s2 = "banana"
    
    # 比较过程:
    # 1. 比较第一个字符: 'a'(97) vs 'b'(98) → 97 < 98
    # 2. 因此 "apple" < "banana",无需比较后续字符
    print("apple" < "banana")  # True
    
  • 示例 2:不同长度字符串的比较

    s1 = "app"
    s2 = "apple"
    
    # 比较过程:
    # 1. 前3个字符相同: 'a','p','p'
    # 2. s1 已结束,s2 还有字符
    # 3. 较短字符串小于较长字符串
    print("app" < "apple")  # True
    

5.4 序列

5.4.1 序列的定义
  • 序列是指内容连续、有序,可使用索引的一类数据容器
  • 列表、元组、字符串、列表均可以被视为序列
5.4.2 序列的常用操作——切片
  • 语法:序列 [起始下标: 结束下标: 步长]
  • 注意:切片操作不会影响序列本身,而是会得到一个新的序列
  • 示例:
    # 对list进行切片,从1开始,到4结束,步长为1
    my_list = [0,1,2,3,4,5,7,8]
    result1 = my_list[1:4]  # 步长默认是1,可以省略不写
    print(result1) # 输出:[1, 2, 3]
    
    # 对tupLe进行切片,从头开始,到最后结束,步长1
    my_tuple = (0, 1, 2, 3, 4, 5, 6)
    result2 = my_tuple[:]  # 起始和结束不写表示从头到尾,步长为1可以省略
    print(result2)   # 输出:(0, 1, 2, 3, 4, 5, 6)
    
    # 对str进行切片,从头开始,到最后结束,步长2
    my_str = "01234567"
    result3 = my_str[::2]
    print(result3)  # 输出:0246
    
    
    # 对str进行切片,从头开始,到最后结束,步长-1
    my_str = "01234567"
    result4 = my_str[::-1]  # 等同于将序列反转了
    print(result4)  # 输出:76543210
    
    
    # 对list进行切片,从3开始,到1结束,步长-1
    my_list =[0,1,2,3,4,5,6]
    result5 = my_list[3:1:-1]
    print(result5) # 输出:[3, 2]
    
    # 对tuple进行切片,从头开始,到尾结束,步长-2
    my_tuple = (0, 1, 2, 3, 4, 5, 6)
    result6 = my_tuple[::-2]
    print(result6)   # 输出:(6,4,2,0)
    

5.5 集合(Set)

5.5.1 集合的定义
  • 集合 是一种 无序、可变、且元素唯一 的数据类型
  • 集合不支持下标索引
5.5.2 基本语法
# 定义集合字面量
{元素,元素,......,元素}
# 定义集合变量
变量名称 = {元素,元素,......,元素}
# 定义空集合
变量名称 = set()
5.5.3 集合的常用操作
创建集合
# 使用花括号创建集合
fruits = {'apple', 'banana', 'cherry'}
num = {1, 2, 3, 4, 5}

# 使用 set() 函数创建集合
empty_set = set()  # 创建空集合
num_set = set([1, 2, 2, 3, 4])  # {1, 2, 3, 4} - 自动去重
添加新元素
fruits = {'apple', 'banana', 'cherry'}
fruits.add("lemon") 
fruits.add("apple") # 重复的元素不会添加
print(fruits)
# 输出:{'apple', 'banana', 'cherry', 'lemon'} 这个顺序随机
移除元素
fruits = {'apple', 'banana', 'cherry'}
fruits.remove("apple")
print(fruits)  # 输出:{'cherry', 'banana'}
随机取出一个元素
fruits = {'apple', 'banana', 'cherry'}
element = fruits.pop()
print(element)   # 输出:banana
print(fruits)    # 输出:{'apple', 'cherry'}
清空集合
fruits = {'apple', 'banana', 'cherry'}
fruits.clear()
print(fruits)  # 输出:set()  空集合的意思
取 2 个集合的差集
set1 = {1, 2, 3}
set2 = {1, 5, 7}
set3 = set1.difference(set2)  # 取出集合1有,而集合2没有的
set4 = set2.difference(set1)  # 取出集合2有,而集合1没有的

print(set3)  # 输出:{2, 3}
print(set4)  # 输出:{5, 7}
print(set1)  # 输出:{1, 2, 3} 
print(set2)  # 输出:{1, 5, 7}
消除 2 个集合的差集
set1 = {1, 2, 3}
set2 = {1, 5, 7}
set1.difference_update(set2)  # 在集合1里,消除和集合2相同的元素

print(set1)  # 输出:{2, 3}      集合1改变
print(set2)  # 输出:{1, 5, 7}   集合2不变
2 个集合合并
set1 = {1, 2, 3}
set2 = {1, 5, 7}
set3 = set1.union(set2)

print(set3)  # 输出:{1, 2, 3, 5, 7}
统计集合元素数量
set1 = {1, 2, 3}
set2 = {1, 2, 3, 1, 2, 3}
num1 = len(set1)
num2 = len(set2)
print(num1)  # 输出:3
print(num2)  # 输出:3
集合的遍历

注意:集合不支持下标索引,不能用 while 循环, 但可以用 for 循环

set1 = {1, 2, 3, 4, 5, 6}
for i in set1:
    print(i)
# 输出:1
#      2
#      3
#      4
#      5
#      6
操作总结
编号操作说明
1集合.add(元素)集合内添加一个元素
2集合.remove(元素)移除集合内指定的元素
3集合.pop()从集合中随机取出一个元素
4集合.clear()将集合清空
5集合 1.difference(集合 2)得到一个新集合,内含 2 个集合的差集,原有的 2 个集合内容不变
6集合 1.difference_update(集合 2)在集合 1 中,删除集合 2 中存在的元素,集合 1 被修改,集合 2 不变
7集合 1.union(集合 2)得到 1 个新集合,内含 2 个集合的全部元素,原有的 2 个集合内容不变
8len(集合)得到一个整数,记录了集合的元素数量

5.6 字典(Dict)

5.6.1 字典的定义
  • 字典 是一种 无序、可变、且键唯一 的数据类型
  • 字典也不支持下标索引
  • 字典的 key 不允许重复,如果重复后面的数据会覆盖前面的
5.6.2 基本语法
# 定义字典字面量
{key: value, key: value, key: value}
# 定义字典变量
my_dict = {key: value, key: value,key: value}
# 定义空字典
my_dict = {}        #空字典定义方式1
my_dict = dict()    #空字典定义方式2
5.6.3 获取字典中的值
# 通过key获取value
my_dict={"小刚":99, "小红":88, "小明":77}
score=my_dict["小刚"]
print(score)   # 输出:99
5.6.4 字典的嵌套

字典的 key 和 value 可以是任意数据类型,但 key 不能是字典类型

#定义嵌套字典
stu_score_dict ={
    "小刚":{"语文":77, "数学":66, "英语":33},
    "小红":{"语文":88, "数学":86, "英语":55},
    "小明":{"语文":98, "数学":76, "英语":75}
}

# 查看嵌套字典的信息
data = stu_score_dict["小刚"]["语文"]
print(data)   # 输出:77
5.6.5 字典的常用操作
新增元素
my_dict={"小刚":99, "小红":88, "小明":77}
 
my_dict["小王"] = 66
print(my_dict)
# 输出:{'小刚': 99, '小红': 88, '小明': 77, '小王': 66}
更新元素
my_dict={"小刚":99, "小红":88, "小明":77}

my_dict["小刚"] = 66
print(my_dict)
# 输出:{'小刚': 66, '小红': 88, '小明': 77}
元素的删除
my_dict={"小刚":99, "小红":88, "小明":77}

# 删除元素  pop(key)
score = my_dict.pop("小红")
print(score)    # 输出:88
print(my_dict)  # 输出:{'小刚': 99, '小明': 77}
清空元素
my_dict={"小刚":99, "小红":88, "小明":77}

# 清空元素 clear()
my_dict.clear()
print(my_dict)  # 输出:{}
获取全部的 key
my_dict={"小刚":99, "小红":88, "小明":77}

# 获取全部key  keys()
keys = my_dict.keys()
print(keys)  # 输出:dict_keys(['小刚', '小红', '小明'])
遍历字典

注意:字典不支持下标索引,不能用 while 循环, 但可以用 for 循环

my_dict={"小刚":99, "小红":88, "小明":77}
# 获取全部key
keys = my_dict.keys()

# 遍历字典
# 方式1:通过获取到全部的key阿里完成遍历
for key in keys:
    print(my_dict[key])  # 输出: 99  88  77
    
# 方式2:直接对字典进行for循环,每一次循环都是直接得到key
for key in my_dict:
    print(my_dict[key])  # 输出: 99  88  77
统计字典内的元素数量
my_dict={"小刚":99, "小红":88, "小明":77}

# 统计元素数量  len()
num = len(my_dict)
print(num)
操作总结
编号操作说明
1字典 [key]获取指定 Key 对应的 Value 值
2字典 [key] = Value添加或更新键值对
3字典.pop(key)取出 Key 对应的 Value 并在字典内删除此 Key 的键值对
4字典.clear()清空字典
5字典.keys()获取字典的全部 Key,可用于 for 循环遍历字典
6len(字典)计算字典内的元素数量

5.7 五类数据容器分类总结

Python 数据类型特性对比

特性列表元组字符串集合字典
定义[]()“”set(){}/dict()
元素数量支持多个支持多个支持多个支持多个支持多个
元素类型任意任意仅字符任意Key: Value
Key: 除字典外任意类型
Value: 任意类型
下标索引支持支持支持不支持不支持
键唯一
重复元素支持支持支持不支持不支持
可修改性支持不支持不支持支持支持
数据有序*
使用场景可修改、可重复的一批数据记录场景不可修改、可重复的一批数据记录场景一串字符的记录场景不可重复的数据记录场景以 Key 检索 Value 的数据记录场景
典型用途动态数据集合不可变数据文本处理去重、集合运算键值对映射

注:Python 3.7+ 的字典保留插入顺序,但本质上仍被认为是无序集合

Python 3.6 之前:字典的键顺序是“无序”的。即使你按顺序插入键值对,遍历字典时可能得到完全不同的顺序(由哈希表实现决定)

5.8 数据容器的通用操作

5.8.1 遍历

首先,在遍历上:

  • 5 类数据容器 都支持 for 循环遍历
  • 列表、元组、字符串支持 while 循环,集合、字典不支持(无法下标索引)
5.8.2 通用统计功能
  • len(容器) :统计容器的元素个数
  • max(容器):统计容器的最大元素
  • min(容器):统计容器的最小元素
5.8.3 通用转换功能
  • list(容器):将给定容器转换为列表

    • 字符串 转换为列表时,每个字符会成为列表的一个元素

      # 字符串转列表
      str_data = "hello"
      list_from_str = list(str_data)  # 结果: ['h', 'e', 'l', 'l', 'o']
      
    • 字典 转换为列表时,只会保留键(key),值(value)会丢失

      # 字典转列表
      dict_data = {'a': 1, 'b': 2}
      list_from_dict = list(dict_data)  # 结果: ['a', 'b']
      
  • tuple(容器):将给定容器转换为元组

    • 字符串 转换为元组时,每个字符会成为元组的一个元素

      # 字符串转元组
      str_data = "hello"
      tuple_from_str = tuple(str_data)  # 结果: ('h', 'e', 'l', 'l', 'o')
      
    • 字典 转换为元组时,只会保留键(key),值(value)会丢失

      # 字典转元组
      dict_data = {'a': 1, 'b': 2}
      tuple_from_dict = tuple(dict_data)  # 结果: ['a', 'b']
      
  • str(容器):将给定容器转换为字符串

    • 列表、元组、集合、字典 转换成字符串, 是,虽然打印输出的时候没有带引号,但是实际上是有引号的

      # 列表转字符串
      list_data = [1, 2, 3]
      str_from_list = str(list_data)  # 实际结果: "[1, 2, 3]"
      print(str_from_list)  # 输出:[1, 2, 3]
      
      # 元组转字符串
      tuple_data = (1, 2, 3, 4)
      str_from_tuple = str(tuple_data)  # 实际结果: "(1, 2, 3, 4)"
      print(str_from_tuple)   # 输出:(1, 2, 3, 4)
      
      # 集合转字符串
      set_data = {1, 2, 3, 4}
      str_from_set = str(set_data)  # 实际结果: "{1, 2, 3, 4}"
      print(str_from_set)   # 输出:{1, 2, 3, 4}
      
    • 字典 转换为字符串时,保留键值对

      # 字典转字符串
      dict_data = {'a': 1, 'b': 2}
      str_from_dict = str(dict_data)  # 实际结果: "{'a': 1, 'b': 2}"
      print(str_from_dict)   # 输出:{'a': 1, 'b': 2}
      
  • set(容器):将给定容器转换为集合

    • 特性

      • 转换后会去除重复元素
      • 顺序会丢失(集合是无序的)
    • 字符串 转换为集合时,每个字符会成为集合的一个元素

      # 字符串转集合,去重并且无序
      str_data = "hello"
      set_from_str = set(str_data)  # 结果: {'h', 'e', 'o', 'l'}
      
    • 字典 转换为集合时,只会保留键(key),值(value)会丢失

      # 字典转集合
      dict_data = {'a': 1, 'b': 2}
      set_from_dict = set(dict_data)  # 结果: {'a', 'b'}
      

没有转字典功能,因为其它数据容器没有键值对

5.8.4 通用排序功能
  • sorted(容器, reverse = True/False):将给定容器进行排序
    • reverse (可选): 布尔值,默认为 False(升序),设为 True 则为降序
    • 排序后的数据类型都为列表,并且 字典只保留建(key)
    • 示例:
      # 对列表排序
      my_list = [3, 1, 2, 5, 4]
      print(sorted(my_list))  # 结果:[1, 2, 3, 4, 5]
      
      # 对元组排序
      my_tuple = (3, 1, 2, 5, 4)
      print(sorted(my_tuple)) # 结果:[1, 2, 3, 4, 5]
      
      # 对字符串排序
      my_str = "bdcefga"
      print(sorted(my_str)) # 结果['a', 'b', 'c', 'd', 'e', 'f', 'g']
      
      # 对集合排序
      my_set = {3, 1, 2, 5, 4}
      print(sorted(my_set))  # 结果:[1, 2, 3, 4, 5]
      
      # 对字典排序
      my_dict = {"key3": 1, "key1": 2, "key2": 3, "key5": 4, "key4": 5}
      print(sorted(my_dict)) # 结果:['key1', 'key2', 'key3', 'key4', 'key5']
      

第六章:函数基础

6.1 函数的定义

组织好的、可重复使用的、用来实现特定功能的代码段

6.2 使用函数的好处

  • 可重用性:写一次,多次使用。
  • 模块化:将复杂问题分解为更小、更易于管理的部分。
  • 可读性:使你的代码更容易理解和维护。

6.3 函数的类型

  • 内置函数
  • 用户定义函数
  • 匿名函数(lambda 函数)

6.4 如何定义函数

  • 基本语法

    def 函数名(参数列表):
      函数体
      return 返回值  # 可选
    
  • 示例

    def greet(name):
      print(f"你好,{name}!")
    
    • def 是 Python 中定义函数的关键字
    • greet 是函数名称
    • (name) 是函数参数列表,表示这个函数需要一个参数 name
    • {name} 会被替换为调用时传入的实际参数值

6.5 如何调用函数

  • 示例:
    # 调用之前定义的函数
    greet("小孤独")  # 输出:你好,小孤独!
    
    • 传递字符串参数 "小孤独"name 参数
    • 函数执行后会输出:你好,小孤独!
  • 执行过程:
    • 当调用 greet("小孤独") 时:
      1. 参数 "小孤独" 被赋值给 name
      2. 执行 print(f"你好, {name}!")
      3. {name} 替换为 “小孤独”,生成字符串 “你好, 小孤独”
      4. 打印到控制台

6.6 函数参数

  • 参数的类型:
    1. 位置参数(Positional Arguments)
    2. 默认参数(Default Arguments)
    3. 可变位置参数(*args)
    4. 可变关键字参数(**kwargs)
    5. 关键字参数(Keyword-Only Arguments)
    6. 仅位置参数(Positional-Only Parameters,使用/分隔)
6.6.1 位置参数
  • 定义时直接写明参数名,调用时按顺序传递值
  • 示例:
    def func(a, b):
      print(a, b)
    func(1, 2)  # 输出: 1 2
    
6.6.2 默认参数
  • 定义时为参数提供默认值,调用时可省略
  • 示例:
    def func(a, b=0):
      print(a, b)
    func(1)      # 输出: 1 0
    func(1, 2)   # 输出: 1 2
    
6.6.3 可变位置参数(*args)
  • 接收任意数量的位置参数,保存为元组
  • 示例:
    def func(a, *args):
      print(a, args)
    func(1, 2, 3,"abc")  # 输出: 1 (2, 3, 'abc')
    
    • 在 Python 中,我们使用 *args 表示 任意参数。这里的星号(*)是神奇的符号,而 args 只是一个约定(你可以使用任何名称,但 args 被广泛使用并认可)。
6.6.4 可变关键字参数(**kwargs)
  • 接收任意数量的关键字参数,保存为字典
  • 示例:
    def func(a, **kwargs):
      print(a, kwargs)
    func(1, b=2, c=3,d="abc")  # 输出: 1 {'b': 2, 'c': 3, 'd': 'abc'}
    
    • 在 Python 中,我们使用 **kwargs 表示 任意关键字参数
6.6.5 关键字参数(Keyword-Only Arguments)
  • **args 之后定义的参数,必须通过关键字传递
  • 示例:
    def func(a, *, b):
      print(a, b)
    func(1, b=2)    # 正确
    func(a=1, b=2)  # 正确
    func(1, 2)      # 报错:TypeError
    
    • * 符号的作用
      • * 在此处是一个语法分隔符,表示其后的参数 b 必须通过 关键字参数(Keyword-Only) 的方式传递,而不能通过位置参数传递。
6.6.6 仅位置参数(Positional-Only Arguments)
  • / 符号前定义的参数,必须通过位置传递
  • 示例:
    def func(a, /, b):
      print(a, b)
    func(1, 2)    # 正确
    func(1, b=2)    # 正确
    func(a=1, b=2) # 报错:TypeError
    
6.6.7 总结表格
参数类型定义语法调用方式用途
位置参数a按顺序传递必须传递的基础参数
默认参数a=0可省略提供默认值,简化调用
可变位置参数(*args)*args任意数量位置参数处理不确定数量的输入
可变关键字参数(**kwargs)**kwargs任意数量关键字参数处理不确定数量的命名参数
关键字参数*, a必须用关键字强制明确参数含义
仅位置参数a, /必须用位置限制参数传递方式(Python 3.8+)

6.7 函数返回值

所谓“返回值”,就是程序中函数完成事情后,最后给调用者的结果

  • 使用 return 返回结果,无返回值时默认返回 None
  • 可返回多个值(实际返回一个元组),返回值可以使用变量接受
  • 函数体在遇到 return 后就结束了,所以写在 return 后的代码不会执行
    • 示例:
      def min_max(numbers):
        return min(numbers), max(numbers)
        print("我不会执行")   # return后面的代码不会执行
      result = min_max([3, 1, 4])
      print(result)  # 输出:(1, 4)
      

None

  • 什么是 None
    • None 是类型 'NoneType' 的字面量用于表示:空的、无意义的
  • 函数如何返回 None
    • 不使用 return 语句即返回 None
    • 主动 return None
  • 使用场景
    • 1.函数返回值
    • 2.if 判断
      • 在 if 判断中,None 等同于 False
      • 一般用于在函数中主动返回 None,配合 if 判断做相关处理
      • 示例:
        def check_age(age) :
        	if age > 18:
        		return "SUCCESS"
        	return None
        
        result = check_age(5)
        if not result:  # not false = true
        	print("未成年,不可进入")
        
    • 3.变量定义
      • 定义变量,但暂时不需要变量有具体值,可以用 None 来代替
      • 示例:
        # 暂不赋予变量具体意义
        name = None
        

6.8 函数说明文档

在 Python 中,函数的 说明文档 通过 文档字符串 来编写,它是函数定义后第一行的多行字符串,用于描述函数的功能、参数、返回值和使用示例

  • 基本语法

    使用 三对双引号 """..."""三对单引号 '''...''' 包裹文档字符串,通常放在函数定义的下一行:

    def func(a, b):
      """
      函数说明
      :param a: 形参a的说明
      :param b: 形参b的说明
      :return: 返回值的说明
      """
      函数体
      return 返回值
    
  • 示例:

    def add(a,b):
      """
      add函数可以接收2个参数,进行2数相加的功能
      :param a:形参a表示相加的其中一个数字
      :param b:形参b表示相加的另一个数字
      :return:返回值是2数相加的结果
      """
      result = a + b
      print(f"两数相加的结果是:{result}")
      return result
    
    add(3,4)
    
    • 鼠标悬停在调用函数的地方”add(3,4)“,会出现如下提示:

      image-20250524132609744

6.9 函数的嵌套调用

函数的嵌套是指在一个函数内部定义另一个函数

  • 示例:

    def func_B():
      print("---2---")
    
    def func_A():
      print("---1---")
      
      func_B()
      
      print("---3---")
    
    # 调用函数func_A
    func_A()
    
    # 输出:
    # ---1---
    # ---2---
    # ---3---
    
  • 执行流程:函数 A 中执行到调用函数 B 的语句,会将函数 B 全部执行完成后,继续执行函数 A 的剩余内容

6.10 变量在函数中的作用域

  • Python 有三种主要的变量作用域
    1. 局部作用域
    2. 全局作用域
    3. 非局部作用域
6.10.1 局部变量
  • 定义:

    在函数内部定义的变量称为局部变量,只在函数体内部生效

  • 示例:

    def my_func():
      x = 10  # 局部变量
      print("函数内访问:", x)
    
    my_func()   # 输出:函数内访问: 10
    print(x)    # 报错:NameError: name 'x' is not defined
    
6.10.2 全局变量
  • 定义:

    在函数外部定义的变量称为全局变量,全局变量在整个文件中有效,可被所有函数访问

  • 示例:

    g = 100  # 全局变量
    
    def func1():
      print("func1 访问全局变量:", g)  # 直接读取
    
    def func2():
      g = 200  # 实际创建了同名局部变量,不会修改全局 g
      print("func2 的局部变量:", g)
    
    func1()  # 输出:func1 访问全局变量: 100
    func2()  # 输出:func2 的局部变量: 200
    print("全局变量未被修改:", g)  # 输出:全局变量未被修改: 100
    

    那么问题来了,怎么在函数内部修改全局变量呢

    很简单,只需要 使用 global 关键字将函数内部定义的变量申明为全局变量,如下:

    g = 100  # 全局变量
    
    def func1():
      print("func1 访问全局变量:", g)  # 直接读取
    
    def func2():
      global g  # global申明 g 是全局变量
      g = 200
      print("func2 访问修改后的全局变量", g)
    
    func1()  # 输出:func1 访问全局变量: 100
    func2()  # 输出:func2 访问修改后的全局变量 200
    print("全局变量已经被修改:", g)  # 输出:全局变量已经被修改: 200
    
6.10.3 非局部变量
  • 定义

    在嵌套函数中,内部函数可以访问外部函数的变量。外层函数的变量对内部函数来说是“非局部(non-local)”的。

  • 示例:

    def outer():
      x = 10  # 外层函数的局部变量(嵌套作用域)
    
      def inner():
    	  print("inner 访问外层变量 x:", x)  # 可读取
    
      inner()
    
    outer()  # 输出:inner 访问外层变量 x: 10
    

    问题又来了,如何在内部函数中修改外层函数的变量呢?

    也很简单,需要 使用 nonlocal 关键字将内层函数中定义的变量申明为非局部变量

    def outer():
      x = 10
      y = 100
    
      def inner():
    	  nonlocal x # nonlocal申明 x 是非局部变量
    	  x = 20  # 修改外层变量
    	  y = 200
    	  print("outer 中的 x:", x)  # 输出:outer 中的 x: 20
    	  print("inner 中的 y:", y)  # 输出:inner 中的 y: 200
    
      inner()
      print("outer 中的 x:", x)  # 输出:outer 中的 x: 20
      print("outer 中的 y:", y)  # 输出:outer 中的 y: 100
    
    outer()
    

第七章:函数进阶

7.1 函数多返回值

基本语法
def test_return():
	return 1, 2

x,y = test_return()
print(x)   # 结果1
print(y)   # 结果2
  • 按照返回值的顺序,写对应顺序的多个变量接受即可
  • 变量之间用逗号隔开
  • 支持不同类型的数据 return
示例
# 演示使用多个变量,接收多个返回值
def test_return():
	return 1,"hello",True
x,y,z= test_return()

print(x)   # 输出:1
print(y)   # 输出:hello
print(z)   # 输出:True

7.2 函数多种传参方式

根据 使用方式上的不同,函数有 4 中常见参数使用方式:位置参数、关键字参数、缺省参数、不定长参数

7.2.1 位置参数
  • 定义:调用函数时,值(实参)会按照顺序依次传递给函数定义时(形参)的位置
  • 示例:
    def greet(name, greeting):
      print(f"{greeting}, {name}!")
    
    # 正确用法:按顺序传递
    greet("Alice", "Hello") # 输出:Hello, Alice!
    
    • Alice 传递给 name参数, Hello 传递给 greeting参数

    注意:传递的参数和定义的参数的顺序及个数必须一致

7.2.2 关键字参数
  • 定义:调用函数时,通过参数名(关键字)来指定值,而不再依赖于位置
  • 作用:可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求
  • 示例:
    def describe_pet(animal_type, pet_name):
      print(f"I have a {animal_type} named {pet_name}.")
    
    # 方式1:传统位置参数
    describe_pet("hamster", "Harry") # 输出:I have a hamster named Harry.
    
    # 方式2:关键字参数(顺序打乱)
    describe_pet(pet_name="Harry", animal_type="hamster") # 输出相同
    
    # 方式3:混合使用(位置参数必须在关键字参数之前)
    describe_pet("hamster", pet_name="Harry") # 正确
    # describe_pet(pet_name="Harry", "hamster") # 语法错误!
    

    注意:函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序

7.2.3 缺省参数(或默认参数)
  • 定义:在函数定义时,为参数指定一个默认值。调用函数时,如果未传递该参数,则使用默认值
  • 作用:当调用函数时没有传递参数,就会默认使用缺省参数对应的值
  • 示例:
    def describe_pet(pet_name, animal_type="dog"): # animal_type 有默认值 "dog"
      print(f"I have a {animal_type} named {pet_name}.")
    
    # 只提供必需的参数 pet_name,animal_type 使用默认值 "dog"
    describe_pet("Willie") # 输出:I have a dog named Willie.
    
    # 提供两个参数,覆盖默认值
    describe_pet("Harry", "hamster") # 输出:I have a hamster named Harry.
    
    # 结合关键字参数,顺序可以任意
    describe_pet(animal_type="cat", pet_name="Mimi") # 输出:I have a cat named Mimi.
    

    注意:在函数定义中,所有带有默认值的参数必须放在没有默认值的参数后面

7.2.4 不定长参数(或可变参数)
  • 定义:用于处理在函数定义时不确定会传入多少个参数的情况。有两种形式:
    • *args :接收任意多个位置参数(位置传递)
    • **kwargs接收任意多个关键字参数(关键字传递)
  • 作用:当调用函数时不确定参数个数时,可以使用不定长参数
  • 示例:
    • *args:在参数前加一个星号 *,函数内部会将这些传入的额外位置参数合并成一个 元组

      def user_info(*name):
        print(name)
      
      user_info('TOM')  # 输出:('TOM',)
      
      user_info('TOM', 'Mike', 'Tony')  # 输出:('TOM', 'Mike', 'Tony')
      
    • **kwargs:在参数前加两个星号 **,函数内部会将这些传入的额外关键字参数合并成一个 字典

      def user_info(**element):
        print(element)
      
      user_info(name = 'TOM', age = 18, gender = "男")  # 输出:{'name': 'TOM', 'age': 18, 'gender': '男'}
      
7.2.5 标准函数定义
  • 正确顺序: 位置参数 -> 缺省参数 -> *args -> **kwargs
  • 标准函数定义模板
    def function_name(positional_args, default_args=value, *args, **kwargs):
      # 函数体
      pass
    
  • 示例
    def complicated_func(a, b, c=10, *args, **kwargs):
      print(f"a: {a}, b: {b}, c: {c}")
      print(f"args: {args}")
      print(f"kwargs: {kwargs}")
    
    complicated_func(1, 2, 3, 4, 5, 6, name="Alice", age=25)
    # 输出:
    # a: 1, b: 2, c: 3
    # args: (4, 5, 6)
    # kwargs: {'name': 'Alice', 'age': 25}
    
7.2.6 总结
参数类型定义语法调用语法作用函数内接收为
位置参数def func(a, b)func(1, 2)必须按顺序传递变量 a, b
关键字参数def func(a, b)func(a=1, b=2)按参数名传递,顺序可变变量 a, b
缺省参数def func(a, b=10)func(1)func(1, 20)参数可省略,使用默认值变量 a, b
不定长参数def func(*args, **kwargs)func(1, 2, x=3, y=4)接收任意数量的参数元组 args, 字典 kwargs

7.3 函数作为参数传递

在前面的函数学习中,我们一直使用的函数,都是接受 数据作为参数 传入:

  • 数字
  • 字符串
  • 字典、列表、元组等

但是,函数的本身也是可以作为参数传入 到另一个函数内

示例

  • greet函数 作为参数传递给 call_function函数
    # 定义一个函数,准备作为参数传入另一个函数
    def greet(name):
      return f"Hello, {name}!"
    
    # 定义一个函数,接受另一个函数作为传入参数
    def call_function(func):
      """接收一个函数作为参数并调用它"""
      result = func("Alice")
      return result
    
    # 将greet函数作为参数传递给call_function
    result = call_function(greet)
    print(result)  # 输出: Hello, Alice!
    

    所以,这是一种,计算逻辑的传递,而非数据的传递

7.4 匿名函数(lambda 函数)

函数的定义中

  • def 关键字,可以定义 带有名称的函数
  • lambda 关键字,可以定义 匿名函数(无名称)

有名称的函数,可以基于名称 重复使用

无名称的匿名函数,只可以 临时使用一次

  • 匿名函数的定义语法:

    lambda 传入参数: 函数体(一行代码)
    
    • lambda:是关键字,表示定义匿名函数
    • 传入参数:表示匿名函数的形式参数,如:×, y 表示接收 2 个形式参数
    • 函数体:就是函数的执行逻辑,要注意:只能写一行,无无法写多行代码
  • 示例

    # 定义一个函数,接受其它函数输入
    def test_function(func):
      result = func(1, 2)
      print(result)  # 输出:3
    
    # 通过Lambda匿名函数的形式,将匿名函数作为参数传入
    test_function(lambda x,y: x+y) 
    

第八章:文件操作

8.1 文件的编码

编码技术 即:翻译的规则,记录了如何将内容翻译成二进制,以及如何将二进制翻译回可识别内容。

计算机中有许多可用编码:

  • UTF-8
  • GBK
  • Big5

不同的编码,将内容翻译成二进制也是不同的

UTF-8 是目前全球通用的编码格式,除非有特殊需求,否则,一律以 UTF-8 格式进行文件编码即可。

8.2 文件的读取

8.2.1 open()函数
  • 基本语法
    open(name, mode, encoding)
    
    • name:是要打开的目标文件名的字符串(可以包含文件所在的具体路径)
    • mode:设置打开文件的模式(访问模式):只读®写入(w)追加(a)
      • 只读®:以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式
      • 写入(w):打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,原有内容会被删除。如果该文件不存在,创建新文件
      • 追加(a):打开一个文件用于追加。如果该文件已存在,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    • encoding:编码格式(推荐使用 UTF-8)
  • 示例
    # 打开文件,并传给文件对象"f"
    f = open("F:/测试.txt","r",encoding="utf-8")
    
    • 前两个参数都是位置参数,第三个参数是关键字参数,因为“encoding”排在第四位,如果直接使用位置参数的形式,数据只会传给“buffering”(第三位)
8.2.2 read()方法
  • 基本语法
    文件对象.read(num)
    
    • num:表示要从文件中读取的数据的长度(单位是字节),如果没有传入 num,那么就表示读取文件中所有的数据
  • 示例
    # 测试.txt文件内容
    # 路上只我一个人,背着手踱着。这一片天地好像是我的;我也像超出了平常旳自己,
    # 到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。
    
    # 打开文件,并传给文件对象"f"
    f = open("F:/测试.txt","r",encoding="utf-8")
    
    # 读取文件 - read()
    result1 = f.read(10)  # 读取10个字节
    print(result1)  # 输出:路上只我一个人,背着
    
    result2 = f.read()   # 读取全部
    print(result2)
    # 输出:手踱着。这一片天地好像是我的;我也像超出了平常旳自己,
    #      到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。
    
    • 问题:从上面输出的 result1 和 result2 中可以看出,result2 输出的内容是 result1 后面没有输出的部分,这是为什么呢?
    • 原因:是因为在 只读® 模式中,指针会随着文件的读取向后移动,当 result1 读取完 10 个字节后,指针停留在了第 11 个字节之前,所以 result2 输出的内容在 result1 之后。
8.2.3 readlines()方法

readlines 可以 按照行的方式 把整个文件中的内容进行 一次性读取,并且返回一个列表,其中 每一行的数据为一个元素

  • 示例
    # 测试.txt文件内容
    # 路上只我一个人,背着手踱着。这一片天地好像是我的;我也像超出了平常旳自己,
    # 到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。
    
    # 打开文件,并传给文件对象"f"
    f = open("F:/测试.txt","r",encoding="utf-8")
    
    # 读取文件 - readlines()
    content = f.readlines()
    print(type(content))  # 输出:<class 'list'>
    print(content)
    # 输出:['路上只我一个人,背着手踱着。这一片天地好像是我的;我也像超出了平常旳自己,\n', '到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。']
    
    • \n:是回车换行符
8.2.4 readline()方法

readline 一次只读取一行内容

  • 示例
    # 读取文件 - readline()
    line1 = f.readline()
    print(line1)  # 输出:路上只我一个人,背着手踱着。这一片天地好像是我的;我也像超出了平常旳自己,
    
    line2 = f.readline()
    print(line2)  # 输出:到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。
    
8.2.5 for 循环读取文件行
  • 示例
    # for循环读取文件行
    for Line in f:
      print(Line)    
    # 输出:路上只我一个人,背着手踱着。这一片天地好像是我的;我也像超出了平常旳自己,
    #      到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。
    
8.2.6 文件的关闭
  • f.close():用来关闭文件
  • close()方法内含 flush()方法
8.2.7 with open 语法
  • 基本语法
    with open("python.txt", "r") as f:
    f.readlines()
    
    • 可以直接在 with open 的语句块中对文件进行操作
    • 使用该语法可以 在操作完成后自动关闭 close 文件,避免遗忘掉 close 方法
  • 示例
    with open("F:/测试.txt","r",encoding="utf-8") as f:
      print(f.read())
    # 输出:路上只我一个人,背着手踱着。这一片天地好像是我的;我也像超出了平常旳自己,
    #      到了另一世界里。我爱热闹,也爱冷静;爱群居,也爱独处。
    
8.2.8 总结
操作功能
文件对象 = open(file, mode, encoding)打开文件获得文件对象
文件对象.read(num)读取指定长度字节
不指定 num 读取文件全部
文件对象.readline()读取一行
文件对象.readlines()读取全部行,得到列表
for line in 文件对象for 循环文件行,一次循环得到一行数据
文件对象.close()关闭文件对象
with open() as f通过 with open 语法打开文件,可以自动关闭

8.3 文件的写入

只需要知道两个方法就行了:

  • write()方法:文件写入
  • flush()方法:内容刷新

示例

# 1.打开文件
f = open('python.txt', "w",encoding="utf-8")
# 2.文件写入
f. write('hello world')
# 3.内容刷新
f.flush()

注意

  • 直接调用 write,内容并未真正写入文件,而是会积攒在程序的内存中,称之为缓冲区
  • 只有当 调用 flush 或者 关闭 close() 的时候,内容才会真正写入文件
  • 这样做是为了避免频繁的操作硬盘,导致效率下降 (攒一堆,一次性写磁盘)

8.4 文件的追加

  • 示例

    #1.打开文件,通过a模式打开即可
    f = open('python.txt','a')
    #2.文件写入
    f.write('hello world')
    #3.内容刷新
    fflush()
    
    
  • 注意

    • a 模式,文件不存在,会创建文件
    • a 模式,文件存在,会在原有内容后面继续写入
    • 可以使用”\n”来写出换行符

第九章:Python 异常、模块与包

9.1 异常的概念

当检测到一个错误时,Python 解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”,也就是我们常说的 BUG

  • 异常演示

    # 通过open,读取一个不存在的文件
    f=open("D:/abc.txt","r", encoding="UTF-8")
    

    出现如下报错

    异常演示

9.2 异常的捕获

世界上没有完美的程序,都会有异常(BUG),所以我们要做的是 异常处理(捕获异常)

捕获异常的作用:提前假设某处会出现异常,做好提前准备,当真的出现异常的时候,可以有后续手段。

9.2.1 基本捕获异常
  • 基本语法
    try:
    可能引发异常的代码
    except:
    处理异常的代码
    
  • 示例
    try:
      f = open("D:/abc.txt", "r", encoding="UTF-8")
    except:
      print("出现异常了,因为文件不存在,我将open的模式,改为w模式去打开")
      f = open("D:/abc.txt", "w", encoding="UTF-8")
    # 输出:
    # 出现异常了,因为文件不存在,我将open的模式,改为w模式去打开
    
9.2.2 捕获指定异常
  • 基本语法
    try:
    可能引发异常的代码
    except 指定异常类型 as e:  # as e 也可以不写 
    处理异常的代码
    
  • 示例

    try:
    print(name)
    except NameError as e:
    print('name变量名称未定义错误") # 输出:name变量名称未定义错误
    
  • 注意事项

    • 如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。
    • 一般 try 下方只放一行尝试执行的代码。
9.2.3 捕获多个异常
  • 基本语法
    • 方式 1:使用多个 except 块

      try:
      	可能引发多种异常的代码
      except 异常类型1:
      	处理第1种异常的代码
      except 异常类型2:
      	处理第2种异常的代码
      except 异常类型3:
      	处理第3种异常的代码 
      

      示例

      # 捕获多个异常
      try:
      	1/0
      #   print(name)
      except NameError:
      	print("出现了变量未定义的异常错误")
      except ZeroDivisionError:
      	print("出现了除以0的异常错误")  # 输出:出现了除以0的异常错误
      
    • 方式 2:在一个 except 块中捕获多个异常

      try:
        可能引发多种异常的代码
      except (异常类型1, 异常类型2, 异常类型3) as e:
        处理这几种异常的代码
      

      示例

      # 捕获多个异常
      try:
        1/0
        # print(name)
      except(NameError, ZeroDivisionError) as e:
        print("出现了变量未定义或者除以0的异常错误")
        # 输出:出现了变量未定义或者除以0的异常错误
      
9.2.4 捕获所有异常
  • 基本语法
    • 方式 1:使用 except Exception(推荐)

      try:
      	可能引发异常的代码
      except Exception as e:
      	处理异常的代码
      
    • 方式 2:使用裸 except 语句(不推荐)

      try:
      	可能引发异常的代码
      except:
      	处理异常的代码
      
9.2.5 异常 else

else 表示的是如果没有异常要执行的代码

  • 基本语法
    try:
      可能引发异常的代码
    except SomeException:
      处理异常的代码
    else:try 块中没有异常发生时执行的代码
    
  • 示例
    try:
      print(1)
    except Exception as e:
      print(e)
    else:
      print("我是else,是没有异常时执行的代码")
      
    # 输出:
    # 1
    # 我是else是没有异常的时候执行的代码
    
9.2.6 异常的 finally

finally 表示的是无论是否异常都要执行的代码,例如关闭文件。

  • 基本语法
    try:
      可能引发异常的代码
    except SomeException:
      处理异常的代码
    # else块可以没有
    else:try 块中没有异常发生时执行的代码
    finally:
      无论是否发生异常都会执行的代码
    
  • 示例
    try:
      f = open("test.txt", "r", encoding="utf-8")  # 打开的是未定义的文件
    except Exception as e:
      print("出现异常")
      f = open("test.txt", "w", encoding="utf-8")
    else:
      print("没有异常")
    finally:
      print("无论是否有异常,finally都要执行")
      f.close()
    # 第1次运行输出:
    # 出现异常
    # 无论是否有异常,finally都要执行
    
    # 第2次运行输出:
    # 没有异常
    # 无论是否有异常,finally都要执行
    

9.3 异常的传递

异常具有传递性:当异常在函数调用栈中未被处理时,会自动向上一层传递,直到被捕获或到达程序顶层(导致程序终止)

  • 基本原理
    def function_a():
      print("函数 A 开始") 
      function_b()  # 调用函数 B
      print("函数 A 结束")  # 这行代码暂时不会执行,等待 function_b 返回
    
    def function_b():
      print("函数 B 开始")  
      function_c()  # 调用函数 C
      print("函数 B 结束")  # 这行代码暂时不会执行,等待 function_c 返回
    
    def function_c():
      print("函数 C 开始") 
      raise ValueError("函数 C 中发生错误")  # 抛出 ValueError 异常
      print("函数 C 结束")  # 这行代码永远不会执行,因为异常已经抛出
    
    # 调用函数 A
    try:
      function_a()
    except ValueError as e:  # 这里捕获到 ValueError 异常
      print(f"捕获到异常: {e}")  
      
    # 输出:
    # 函数 A 开始
    # 函数 B 开始
    # 函数 C 开始
    # 捕获到异常: 函数 C 中发生错误
    
  • 解释
    • 第 1 步:调用 function_a()

      try:
      	function_a()  # 从这里开始执行
      
    • 第 2 步:执行 function_a()

      def function_a():
      	print("函数 A 开始")  # 输出: "函数 A 开始"
      	function_b()  # 调用函数 B,控制权转移到 function_b
      	print("函数 A 结束")  # 这行代码暂时不会执行,等待 function_b 返回
      
    • 第 3 步:执行 function_b()

      def function_b():
      	print("函数 B 开始")  # 输出: "函数 B 开始"
      	function_c()  # 调用函数 C,控制权转移到 function_c
      	print("函数 B 结束")  # 这行代码暂时不会执行,等待 function_c 返回
      
    • 第 4 步:执行 function_c() - 异常发生点

      def function_c():
          print("函数 C 开始")  # 输出: "函数 C 开始"
          raise ValueError("函数 C 中发生错误")  # 抛出 ValueError 异常
          print("函数 C 结束")  # 这行代码永远不会执行,因为异常已经抛出
      
    • 第 5 步:异常开始传递

      • 异常首先在 function_c() 中查找处理
        • function_c() 内部没有 try-except 块来处理这个异常
        • 所以异常会向上传递到调用 function_c() 的地方
      • 异常传递到 function_b()
        • 异常出现在 function_b()function_c() 调用处
        • function_b() 内部也没有 try-except 块来处理这个异常
        • 所以异常继续向上传递到调用 function_b() 的地方
      • 异常传递到 function_a()
        • 异常出现在 function_a()function_b() 调用处
        • function_a() 内部也没有 try-except 块来处理这个异常
        • 所以异常继续向上传递到调用 function_a() 的地方
    • 第 6 步:异常在顶层被捕获

      try:
      	function_a()  # 异常传递到这里
      except ValueError as e:  # 这里捕获到 ValueError 异常
      	print(f"捕获到异常: {e}")  # 输出: "捕获到异常: 函数 C 中发生错误"
      

[!ATTENTION] 注意
当所有函数都没有捕获异常的时候,程序就会报错

  • 异常传递的重要性,因为:
    1. 允许集中错误处理:不需要在每个函数中都处理异常,可以在合适的层级统一处理
    2. 保持代码简洁:底层函数可以专注于业务逻辑,错误处理可以放在更高层级
    3. 提供完整的错误上下文:异常传递会保留完整的调用栈信息,便于调试

9.4 Python 模块

9.4.1 模块的导入
模块的定义

Python 模块(Module),是一个个 Python 文件.py 结尾。模块能定义函数、类和变量,模块里也能包含可执行的代码。

模块的作用
  1. 代码重用
    • 把常用功能封装成模块,避免重复造轮子
    • 一次编写,多处使用
  2. 命名空间
    • 不同模块可以有同名函数,不会冲突
    • 通过 模块名.函数名 清晰区分
  3. 组织性与可维护性
    • 大型项目可以按功能拆分成多个模块
    • 代码结构清晰,便于团队协作和维护
  4. 第三方库
    • Python 有丰富的生态系统(NumPy、Pandas、Requests 等)
    • 直接使用成熟方案,提高开发效率
模块的导入方式

模块在使用前要先导入

  • 基本语法

    # [] :表示可选
    [from 模块名] import [模块 || 变量 | 函数 | *] [as 别名]
    
  • 常用的组合如下

    1. import 模块名

      • 基本语法

        import 模块名
        import 模块名1,模块名2
        
        模块名.功能名()
        
      • 示例

        # 使用import导入time模块使用sLeep功能(函数)
        
        import time # 导入Python内置的time模块(time.py这个代码文件)
        print("你好")
        
        time.sleep(5) # 睡眠5秒钟
        print("我好")
        
    2. from 模块名 import 功能名

      • 基本语法

        # 当功能名过长时可以取别名
        # []:可选
        from 模块名 import 功能名 
        功能名()
        
      • 示例

        # 使用from导入time的sLeep功能(函数)
        from time import sleep
        print("你好")
        
        sleep(5)
        print("我好")
        
    3. from 模块名 import

      • 基本语法

        # *:表示模块的全部功能
        from 模块名 import *
        功能名()
        
      • 示例

        # 使用*导入time模块的全部功能
        from time import *  # *:表示全部的意思
        print("你好")
        sleep(5)  # 不需要写time.sleep(),可以直接写sleep()
        print("我好")
        
    4. as 定义别名

      • 基本语法

        # 模块定义别名
        import 模块名 as 别名
        模块别名.功能名()
        
        # 功能定义别名
        from 模块名 import 功能 as 别名
        功能别名()
        
      • 示例

        # 使用as给特定模块加上别名
        import time as t
        print("你好")
        t.sleep(5)  # 不能再用time.sleep(),需要使用t.sleep()
        print("我好")
        
        # 使用as给特定功能加上别名
        from time import sleep as sl
        print("你好")
        sl(5)  # 不能再用sleep(),需要使用是s1()
        print("我好")
        
9.4.2 自定义模块

Python 中已经帮我们实现了很多的模块,不过有时候我们需要一些个性化的模块,这里就可以通过自定义模块实现,也就是自己制作一个模块。

案例演示
  • 第 1 步:创建一个名为 mymodule1.py 的文件

    def test(a, b):
    print(a + b)
    
  • 第 2 步:导入自定义模块并使用

    import mymodule1
    
    mymodule1.test(12,13) # 输出:25
    
注意事项
  • 示例

    # mymodule1.py,即模块1代码
    def test(a, b):
    print(a + b)
    
    # mymodule2.py,即模块2代码
    def test(a, b):
      print(a - b)
    
    # 导入模块和调用功能代码
    from mymodule1 import test
    from mymodule2 import test
    
    # test函数是模块2中的函数
    test(2, 5)  # 输出:-3
    

    导入多个模块 的时候,且模块内有 同名功能,当调用这个同名功能的时候,调用到的是 后面导入的模块的功能

测试模块(__name__ 变量)

在实际开发中,当开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在 .py 文件中添加一些 测试信息,例如,在 mymodule1.py 文件中添加 测试代码 test(2,3)

  • 示例
    # mymodule1.py,即模块1代码
    def test(a, b):
    print(a + b)
      
    test(2,3)
    
    • 当运行时,就会 出现问题
      • 无论是当前文件,还是其他已经导入了该模块的文件,在运行的时候都会自动执行 test 函数的调用
  • 解决方法:使用 __name__ 变量
    # mymodule1.py,即模块1代码
    def test(a, b):
    print(a + b)
      
    # 只在当前文件中调用该函数,其他导入的文件内不符合该条件,则不执行test函数调用
    if __name__ == "__main__":
      # 当模块直接运行时执行
    test(2,3)
    
__all__ 变量

如果一个模块文件中有 __all__ 变量,当使用 from xxx import * 导入时,只能导入这个列表中的元素

  • 示例

    mymodule1.py 文件中有如下代码

    # mymodule1.py,即模块1代码
    __all__ = ["testA"]  # 使用`from xxx import *`导入时,只能使用"testA"功能
    
    def testA():
    	print("testA")
    
    def testB():
    	print("testB")
    

    然后在 test.py 测试,结果如下

    PixPin_2025-09-27_21-39-49

    从图中可知,因为 __all__ 变量里只写了 testA ,所以使用 from xxx import * 导入时,只可以使用 testA 功能

9.5 Python 包

9.5.1 Python 包的概念

从物理上看,包就是一个 文件夹,在该文件夹下包含了一个 __init__·py 文件,该文件夹可用于 包含多个模块文件
从逻辑上看,包的本质依然是 模块

__init__.py 文件的作用:

创建包会默认自动创建的文件,通过这个文件来表示一个文件夹是 Python 的包,而非普通的文件夹。

包的作用

当我们的模块文件越来越多时,包可以帮助我们管理这些模块,包的作用就是包含多个模块,但包的本质依然时模块

9.5.2 自定义 Python 包

步骤如下:

  1. 新建包 my_package

  2. 新建包内模块:my_module1my_module2

  3. 模块内代码如下

    • my_module1.py

      # my_module1模块中
      
      def info_print1():
         print('my_module1')
      
    • my_module2.py

      # my_module2模块中
      
      def info_print2():
         print('my_module2')
      

使用自定义的包

  • 方式 1

    • 基本语法

      import 包名.模块名
      包名.模块名.目标
      
      # 或者
      from 包名 import 模块名
      模块名.目标
      
      # 再或者
      from 报名.模块名.目标
      目标
      
    • 示例

      # 导入自定义的包中的模块,并使用
      import my_package.my_module1
      import my_package.my_module2
      
      my_package.my_module1.info_print1() # 输出:my_module1
      my_package.my_module2.info_print2() # 输出:my_module2
      

      或者

      # 导入自定义的包中的模块,并使用
      from my_package import my_module1
      from my_package import my_module2
      
      my_module1.info_print1() # 输出:my_module1
      my_module2.info_print2() # 输出:my_module2
      

      再或者

      # 导入自定义的包中的模块,并使用
      from my_package.my_module1 import info_print1
      from my_package.my_module2 import info_print2
      
      info_print1() # 输出:my_module1
      info_print2() # 输出:my_module2
      
  • 方式 2

    注意:必须在 __init__·py 文件中添加 __all__=[],控制允许导入的模块列表

    • 基本语法

      from 包名 import *
      模块名.目标
      
    • 示例

      • __init__.py 文件中添加如下代码

        # 控制要导入的模块
        __all__ = ['my_module1']
        
      • 在测试文件 test.py 中添加如下代码

        # 通过__all__变量,控制import *
        from my_package import *
        my_module1.info_print1() # 输出:my_module1
        # my_module2.info_print2()  报错
        
9.5.3 Python 第三方包的概念

Python 第三方包(也称为 模块)是由全球各地的开发者、公司或社区(即“第三方”,而非 Python 官方)创建的、预先编写好的代码集合。它们被设计用来解决特定的问题或提供特定的功能,你可以将它们“安装”到你的 Python 环境中,然后像使用内置功能一样来使用它们,从而避免重复造轮子。

在 Python 程序的生态中,有许多非常多的第三方包(非 Python 官方),可以极大的帮助我们提高开发效率,如:

  • 科学计算中常用的:numpy 包
  • 数据分析中常用的:pandas 包
  • 大数据计算中常用的:pyspark、apache-flink 包
  • 图形可视化常用的:matplotlib、pyecharts
  • 人工智能常用的:tensorflow
如何获取和管理第三方包?

这一切都通过 Python 的包管理工具 pip 来完成。

  1. 安装包

    在命令行(终端/CMD)中使用以下命令:

    pip install 包名
    

    例如,安装 requests 包:

    pip install requests
    

    pip 会自动从 PyPI 下载该包及其所有依赖项,并安装到你的 Python 环境中。

    [!INFO]
    PyPI:Python 包索引,一个巨大的公共仓库,存放着几乎所有 Python 第三方包

  2. 查看已安装的包

    pip list
    
  3. 卸载包

    pip uninstall 包名
    
pip 网络优化

由于网络原因,直接使用 pip 从官方源(PyPI)安装包在中国大陆可能会非常慢,甚至经常超时失败。下面是解决方法

方法:使用国内镜像源(最常用、最有效)

这是最推荐的方法。国内许多高校和组织提供了 PyPI 的镜像,它们会定时与官方源同步。

  • 常用国内镜像源列表

    • 清华镜像https://pypi.tuna.tsinghua.edu.cn/simple/
    • 阿里云https://mirrors.aliyun.com/pypi/simple/
    • 中国科技大学https://pypi.mirrors.ustc.edu.cn/simple/
    • 豆瓣http://pypi.douban.com/simple/ (注意是 http)
    • 华为云https://repo.huaweicloud.com/repository/pypi/simple/
  • 使用方法

    1. 临时使用(单次安装)

      pip install 命令后加上 -i--index-url 参数指定镜像源。

      # 这里使用清华的镜像
      pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple/
      
    2. 设为默认(一劳永逸)

      将镜像源写入 pip 的配置文件中,这样以后所有 pip install 命令都会自动使用它。

      • 命令行配置(推荐)

        # 为清华源为例
        pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/
        # 如果上面的命令因为信任问题失败,可以添加信任主机
        pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn
        
      • 手动编辑配置文件

        对于不同系统,配置文件的位置如下:

        • Linux/macOS: ~/.pip/pip.conf~/.config/pip/pip.conf
        • Windows: %APPDATA%\pip\pip.ini (例如: C:\Users\你的用户名\AppData\Roaming\pip\pip.ini) 或 C:\PythonXX\Lib\site-packages\pip\
        • 通过“where pip”查看 pip 文件位置

        文件内容为:

        [global]
        index-url = https://pypi.tuna.tsinghua.edu.cn/simple/
        trusted-host = pypi.tuna.tsinghua.edu.cn
        

第十章:面向对象

面向对象编程(OOP)是一种编程范式,它将数据和对数据的操作封装在一起,形成 “对象”。Python 是一门完全支持面向对象编程的语言。

10.1 初识对象

对象 是类的实例,包含数据和操作数据的方法。

使用对象组织数据

在程序中是可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的。

  1. 在程序中 设计表格,我们称之为:设计类(class)

    class Student:
    name = None # 记录学生姓名
    
  2. 在程序中 打印生产表格,我们称之为:创建对象

    #基于类创建对象
    stu_1 = Student()
    stu_2 = Student()
    
  3. 在程序中 填写表格,我们称之为:对象属性赋值

    stu_1.name = "周杰轮" # 为学生1对象赋予名称属性值
    stu_2.name = "林军杰" # 为学生2对象赋予名称属性值
    

示例

# 1.设计一个类(类比生活中:设计一张登记表)
class Student:
    name =None # 记录学生姓名
    gender =None # 记录学生性别
    nationality = None # 记录学生国籍
    native_place =None # 记录学生籍贯
    age = None # 证录学生年龄
# 2.创建一个对象(类比生活中:打印一张登记表)
stu_1 = Student()
# 3.对象属性进行赋值(类比生活中:填写表单)
stu_1.name="林军杰"
stu_1.gender="男"
stu_1.nationality = "中国"
stu_1.native_place = "山东省"
stu_1.age = 31
# 4.获取对象中记录的信息
print(stu_1.name)  # 林军杰
print(stu_1.gender)  # 男
print(stu_1.nationality) # 中国
print(stu_1.native_place) # 山东省
print(stu_1.age) # 31

10.2 类和对象

10.2.1 类的定义和使用
类的使用语法
class 类名称:
    类的属性
    
    类的行为
  • class 是关键字,表示要定义类了
  • 类的属性,即定义 在类中的变量 (成员变量)
  • 类的行为,即定义 在类中的函数 (成员方法)

[!INFO] 注意:函数是写在类外的,定义在类内部,我们都称之为方法哦

创建类对象的语法
对象 = 类名称()
10.2.2 成员变量和成员方法

成员方法定义语法

在类中定义成员方法和定义函数基本一致,但仍有细微区别:

def 方法名(self, 形参1, ..., 形参n):
    方法体

示例

"""
演示面向对象类中的成员方法定义和使用
"""
# 定义一个带有成员方法的类
class Student:
    name = None  # 学生的姓名

    def say_hi(self):
        print(f"大家好呀,我是{self.name},欢迎大家多多关照")

stu = Student()
stu.name ="周杰轮"
stu.say_hi()  # 大家好呀,我是周杰轮,欢迎大家多多关照

stu2 = Student()
stu2.name="林俊节"
stu2.say_hi()  # 大家好呀,我是林俊节,欢迎大家多多关照
10.2.3 self 关键字

self 关键字是成员方法定义的时候,必须填写的

  • 它用来表示类对象自身的意思
  • 当我们使用类对象调用方法的是,self 会自动被 Python 传入
  • 在方法内部,想要访问类的成员变量,必须使用 self
  • self 关键字,尽管在参数列表中,但是 传参的时候可以忽略它

10.3 构造方法

class Student:
    name=None # 名称
    age=None  # 年龄
    tel=None  # 手机号

studentl = Student()
studentl.name="周杰轮"
studentl.age=31
studentl.tel = "18012340000"

[!QUESTION] 上面的代码中,为对象的属性赋值需要依次进行,略显繁琐。有没有更加高效的方式,能够一行代码就完成呢?

当然有,可以使用构造方法:__init__()

构造方法的作用:

  • 在创建类对象(构造类)的时候,会自动执行
  • 在创建类对象(构造类)的时候,将传入参数自动传递给 __init__ 方法使用。

示例

# 创建一个简单的对象
class Student:
    # 初始化方法(构造函数)
    def __init__(self, name, age):  
        # 实例属性(每个实例独有)
        self.name = name
        self.age = age
    
    # 实例方法
    def introduce(self):
        return f"我叫{self.name},今年{self.age}岁"

# 创建对象实例
student1 = Student("张三", 18)
print(student1.introduce())  # 输出:我叫张三,今年18岁
  • __init__:类的构造方法,当创建类的实例时会自动调用,用于初始化实例的属性

注意事项

  • 构造方法也是成员方法,不要忘记在参数列表中提供:self
  • 在构造方法内定义成员变量,需要 使用 self 关键字
    • 原因:因为变量是定义在构造方法内部,如果 要成为成员变量,需要用 self 来表示

10.4 魔术方法

上文学习的 __init__ 构造方法,是 Python 类内置的方法之一。
这些内置的类方法,各自有各自特殊的功能,这些内置方法我们又称之为:魔术方法

常见的魔术方法

  • __init__:构造方法
  • __str__:字符串方法
  • __lt__:小于、大于符号比较
  • __le__:小于等于、大于等于符号比较
  • __eq__:== 符号比较
10.4.1 __str__ 字符串方法

当类对象需要被转换为字符串时,会输出如下结果(内存地址)

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

student = Student("周杰轮", 11)
print(student) # 输出:<__main__.Student object at 0x000001F50D44C6E0>
print(str(student)) # 输出:<__main__.Student object at 0x000001F50D44C6E0>

内存地址没有多大作用,我们可以通过 __str__ 方法,控制类转换为字符串的行为

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"Student类对象,name={self.name},age={self.age}"

student = Student("周杰轮", 11)
print(student)  # 输出:Student类对象,name=周杰轮,age=11
print(str(student)) # 输出:Student类对象,name=周杰轮,age=11
10.4.2 __lt__ 小于比较方法

直接比较两个对象会报错

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

stu1 = Student("周杰轮", 11)
stu2 = Student("林军杰", 13)
print(stu1 < stu2)
# 报错信息如下
"""
Traceback (most recent call last):
  File "F:\Python-learn\test.py", line 9, in <module>
    print(stu1 < stu2)
          ^^^^^^^^^^^
TypeError: '<' not supported between instances of 'Student' and 'Student'
"""

但是在类中实现 __lt__ 方法,即可同时完成:小于符号和大于符号 2 种比较

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __lt__(self, other):
        return self.age < other.age  # other:另一个参数对象

stu1 = Student("周杰轮", 11)
stu2 = Student("林军杰", 13)
print(stu1 < stu2)  # 输出:True
print(stu1 > stu2)  # 输出:False
10.4.3 __le__ 小于等于比较方法

可用于:<=、> = 两种比较运算符上

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __le__(self, other):
        return self.age <= other.age  # other:另一个参数对象

stu1 = Student("周杰轮", 11)
stu2 = Student("林军杰", 13)
stu3 = Student("吴彦主", 11)
print(stu1 <= stu2)  # 输出:True
print(stu1 >= stu2)  # 输出:False
print(stu1 >= stu3)  # 输出:True
print(stu1 <= stu3)  # 输出:True
10.4.4 __eq__ == 符号比较方法

不实现 __eq__ 方法,对象之间可以比较,但是比较的是内存地址,即:不同对象 == 比较,一定是 False

class Student:
    def __init__(self, name, age) :
        self.name = name
        self.age = age

stu1 =Student("周杰轮", 11)
stu2 = Student("林军杰", 11)
print(stu1)  # 输出:<__main__.Student object at 0x0000013102D4C6E0>
print(stu2)  # 输出:<__main__.Student object at 0x0000013102E12990>
print(stu1 == stu2) # 结果:False

实现了 __eq__ 方法,就可以按照自己的想法来决定 2 个对象是否相等了

class Student:
    def __init__(self, name, age) :
        self.name = name
        self.age = age

    def __eq__(self, other): # other:另一个参数对象
        return self.age == other.age

stu1 =Student("周杰轮", 11)
stu2 = Student("林军杰", 11)
print(stu1 == stu2) # 结果:True

10.5 封装

面向对象编程的三大特性为:封装,继承,多态

封装 表示的是,将现实世界事物的属性和行为,封装到类中,描述为成员变量和成员方法,从而完成程序对现实世界事物的描述

但是现实世界中事物的属性和行为并不是都是开发给用户使用的,所以作为现实事物在程序中映射的类也是这样的

私有成员的形式
  • 私有成员变量
  • 私有成员方法
定义私有成员
  • 私有成员变量:变量名以 __ 开头 (2 个下划线)
  • 私有成员方法:方法名以 __ 开头(2 个下划线)

示例

class Phone:
    IMEI = None # 序列号
    producer = None # 厂商

    # 私有成员变量
    __current_voltage = None # 当前电压

    def call_by_5g(self):
        print("5g通话已开启")

    # 私有成员方法
    def __keep_single_core(self):
        print("让CPU以单核模式运行以节省电量")
名称转写

以双下划线开头,并以最多一个下划线结尾 的标识符,例如 __X,会被转写为 _classname__X,其中 classname 为类名。这个机制实现起来非常简单,而且很大程度避免了调用者的误访问,但并不能像 Java 的 private 限定符那样 完全杜绝 外部的访问。具体的例子如下:

私有方法无法直接被类对象使用

class Phone:
  def call_by_5g(self):
	  print("5g通话已开启")

  # 私有成员方法
  def __keep_single_core(self):
	  print("让CPU以单核模式运行以节省电量")

# 创建对象
phone = Phone()
# 使用私有方法
phone.__keep_single_core()
# 报错如下
"""
Traceback (most recent call last):
File "F:\Python-learn\test.py", line 18, in <module>
  phone.__keep_single_core()
  ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Phone' object has no attribute '__keep_single_core'. Did you mean: '_Phone__keep_single_core'?
"""
  • 从报错中可以看出 __keep_single_core 方法并不存在,被转写后的方法真实名称是 _Phone__keep_single_core

私有变量无法赋值,也无法获取值

class Phone:
  IMEI = None # 序列号
  Producer = None # 厂商

  # 私有成员变量
  __current_voltage = None # 当前电压

# 创建对象
phone = Phone()
# 查看phone对象的所有属性
print(dir(phone))   # ['IMEI', 'Producer', '_Phone__current_voltage', '__class__', '__delattr__',....]
# 查看被转写的私有变量(不建议)
print(phone._Phone__current_voltage)  # None

# 这不是私有变量赋值,本质上是新增的普通实例属性
phone.__current_voltage = 44
print(phone.__current_voltage) # 44

# 查看新增的属性
print(dir(phone))   # 'IMEI', 'Producer', '_Phone__current_voltage', '__class__', '__current_voltage', '__delattr__',...]
  • 从上面的输出可以看出,私有变量 __current_voltage 被转写成了 _Phone__current_voltage,所以输出为 None
  • 并且 __current_voltage 属性是新增的
私有成员的使用

私有成员无法被类对象使用,但是可以被其它的成员使用

class Phone:
    # 私有成员变量
    __current_voltage = 1 # 当前电压

    # 私有成员方法
    def __keep_single_core(self):
        print("让CPU以单核模式运行以节省电量")

    def call_by_5g(self):
        if self.__current_voltage >= 1:
            print("5g通话已开启")

phone = Phone()
phone.call_by_5g()  # 5g通话已开启

10.6 继承

在 Python 中,继承是面向对象编程(OOP)的核心特性之一,它允许一个类(称为 子类 / 派生类)继承另一个类(称为 父类 / 基类)的属性和方法,从而实现代码复用、简化逻辑并建立类之间的层次关系。

基本概念
  • 父类(基类):被继承的类,包含通用的属性和方法。
  • 子类(派生类):继承父类的类,可复用父类的功能,也可添加自己的属性 / 方法,或修改父类的方法(重写)。
基本语法

定义子类时,在类名后通过括号指定要继承的父类

# 父类
class 父类名:
    # 父类的属性和方法
    pass

# 子类(继承父类)
class 子类名(父类名):
    # 子类的属性和方法(可新增或重写)
    pass
核心特性
01.继承父类的属性和方法

子类实例可以直接使用父类中定义的属性和方法,无需重复编写

# 父类:动物(通用属性和方法)
class Animal:
    def __init__(self, name):
        self.name = name  # 父类的属性

    def eat(self):  # 父类的方法
        print(f"{self.name}在吃东西")

# 子类:狗(继承Animal)
class Dog(Animal):
    pass  # 暂时不添加新内容

# 实例化子类
dog = Dog("旺财")
print(dog.name)  # 继承父类的属性:输出 "旺财"
dog.eat()        # 继承父类的方法:输出 "旺财在吃东西"
02.子类新增属性和方法

子类可以在父类基础上添加自己特有的属性或方法,扩展功能

class Dog(Animal):
    # 子类新增方法
    def bark(self):
        print(f"{self.name}在汪汪叫")

dog = Dog("旺财")
dog.bark()  # 子类特有方法:输出 "旺财在汪汪叫"
03.重写父类的方法

如果子类对父类的方法不满意,可以 重写(覆盖)父类的方法(方法名与父类相同),实现自定义逻辑

class Dog(Animal):
    # 重写父类的eat方法
    def eat(self):
        print(f"{self.name}在啃骨头(重写后的eat方法)")

dog = Dog("旺财")
dog.eat()  # 调用子类重写的方法:输出 "旺财在啃骨头(重写后的eat方法)"
04.调用父类的方法(super() 函数)

如果子类重写了父类的方法,但仍想使用父类的原始逻辑,可以通过 super() 函数调用父类的方法

class Animal:
    def __init__(self, name):
        self.name = name

class Dog(Animal):
    def __init__(self, name, breed):  # 子类新增breed属性
        # 调用父类的__init__方法,初始化name属性
        super().__init__(name)  
        self.breed = breed  # 子类自己的属性

    def info(self):
        # 调用父类的属性,结合子类的属性
        print(f"名字:{self.name},品种:{self.breed}")

dog = Dog("旺财", "金毛")
dog.info()  # 输出 "名字:旺财,品种:金毛"
多继承

Python 支持 多继承:一个子类可以同时继承多个父类(用逗号分隔父类)

基本语法
class 子类名(父类1, 父类2, ...):
    pass

示例

class Flyable:  # 父类1:会飞
    def fly(self):
        print("我会飞")

class Swimmable:  # 父类2:会游泳
    def swim(self):
        print("我会游泳")

class Duck(Flyable, Swimmable):  # 鸭子同时继承两个父类
    pass

duck = Duck()
duck.fly()   # 继承Flyable的方法:输出 "我会飞"
duck.swim()  # 继承Swimmable的方法:输出 "我会游泳"
多继承的注意事项:方法解析顺序(MRO)

当多个父类有同名方法时,子类调用该方法会遵循 MRO(Method Resolution Order) 规则(Python3 使用 C3 线性化算法),可通过 类名.__mro__ 查看顺序。

class A:
    def func(self):
        print("A的func")

class B(A):
    def func(self):
        print("B的func")

class C(A):
    def func(self):
        print("C的func")

class D(B, C):
    pass

# 查看D的MRO:D → B → C → A → object
print(D.__mro__)  # 输出 (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

d = D()
d.func()  # 按MRO顺序调用B的func:输出 "B的func"
  • 多继承中,同名方法的调用遵循 MRO 顺序,第一个被找到的方法会被执行。这个例子中 B 在 MRO 中位于 C 之前,且 Bfunc 方法,因此最终执行的是 Bfunc
私有成员的继承

父类中以 __ 开头的 私有属性 / 方法(如 __x)不能被子类直接访问(但可通过父类的公有方法间接访问)

class Parent:
    def __init__(self):
        self.__secret = "这是秘密"  # 私有属性

    def get_secret(self):  # 公有方法,用于访问私有属性
        return self.__secret

class Child(Parent):
    def try_access(self):
        # print(self.__secret)  # 报错:直接访问私有属性失败
        return self.get_secret()  # 通过父类公有方法访问

child = Child()
print(child.try_access())  # 输出 "这是秘密"

10.7 类型注解

在 Python 中,类型注解(Type Hints) 是一种语法机制,用于为变量、函数参数、返回值等指定 预期的数据类型。它的核心作用是提升代码的可读性、可维护性,并帮助开发者和工具(如 IDE、静态类型检查器)提前发现潜在的类型错误。

基本概念

类型注解是 可选的:Python 是动态类型语言,运行时不会强制检查类型是否匹配(即使注解与实际类型不符,代码也能运行)。

  • 主要用途:
    • 明确代码意图,让其他开发者(或未来的自己)快速理解变量 / 函数的类型约束。
    • 辅助 IDE 实现更精准的自动补全、语法提示。
    • 配合静态类型检查工具(如 mypy)在运行前检测类型错误。
  • 支持:
    1. 变量的类型注解
    2. 函数的类型注解
    3. 复杂类型的注解
    4. 特殊类型的注解
    5. 类与对象的注解
基本语法
01.变量的类型注解

为变量指定预期类型,语法为 变量名: 类型 = 值(赋值可选)

# 基本类型注解
age: int = 25  # 整数
name: str = "Alice"  # 字符串
is_student: bool = True  # 布尔值
height: float = 1.75  # 浮点数

# 未赋值的变量也可以注解
score: float  # 后续会赋值为float类型
score = 95.5  # 符合注解
02.函数的类型注解

为函数参数和返回值指定类型,参数注解用 参数名: 类型,返回值注解用 -> 类型 放在函数定义末尾

# 函数参数和返回值注解
def add(a: int, b: int) -> int:
    return a + b

# 调用函数时,即使传入非int类型也能运行(动态类型特性)
result = add(3.5, 4)  # 实际传入float,运行不报错,但不符合注解
  • 函数注解仅表示 “预期”,不影响运行,但静态检查工具(如 mypy)会提示类型不匹配
03.复杂类型的注解

对于列表、字典、元组等复合类型,需要指定内部元素的类型。Python 3.9+ 支持直接用内置类型(如 list[int]),低版本需用 typing 模块(如 List[int]

Python 3.9 及以上

  • 基础

    # 列表
    nums: list = [1, 2, 3]  # Python 3.9+
    # 字典
    user: dict = {"age": 25, "score": 90}  # Python 3.9+
    # 元组
    person: tuple = ("Alice", 25)   # Python 3.9+
    # 集合
    floats: set = {1.1, 2.2}    # Python 3.9+
    
  • 详细

    # 列表(元素类型为int)
    nums: list[int] = [1, 2, 3]  # Python 3.9+
    # 字典(键为str,值为int)
    user: dict[str, int] = {"age": 25, "score": 90}  # Python 3.9+
    # 元组(固定长度和类型,第一个元素str,第二个int)
    person: tuple[str, int] = ("Alice", 25)   # Python 3.9+
    # 集合(元素类型为float)
    floats: set[float] = {1.1, 2.2}    # Python 3.9+
    

    注意

    • 元组类型设置类型详细注解,需要将每一个元素都标记出来
    • 字典类型设置类型详细注解,需要 2 个类型,第一个是 key,第二个是 value
04.特殊类型的注解
  • 可选类型(可能为 None:用 Optional[类型](Python 3.10+ 可用 类型 | None
  • 联合类型(多种可能类型):用 Union[类型1, 类型2](Python 3.10+ 可用 类型1 | 类型2
  • 函数类型:用 Callable 表示函数对象的类型

示例

from typing import Optional, Union, Callable

# 可选类型:可以是int或None
optional_num: Optional[int] = None
optional_num_new: int | None = 10  # Python 3.10+

# 联合类型:可以是int或str
union_val: Union[int, str] = "hello"
union_val_new: int | str = 100  # Python 3.10+

# 函数类型:接收int和str,返回bool的函数
func_type: Callable[[int, str], bool] = lambda x, y: x > len(y)
05.类与对象的注解

可以直接用类名作为类型,指定变量或参数为某个类的实例

class Person:
    def __init__(self, name: str):
        self.name = name

# 注解为Person类的实例
p: Person = Person("Bob")

# 函数参数注解为Person实例
def greet(person: Person) -> str:
    return f"Hello, {person.name}"
类型注解的工具
  1. IDE 支持:PyCharm、VS Code(配合 Python 插件)会根据注解提供自动补全、类型错误提示。

  2. 静态类型检查器 mypy

    • 安装:pip install mypy
    • 使用:在终端运行 mypy 文件名.py,会检查代码中类型注解与实际使用的不一致。

    例如,对以下代码运行 mypy

    def add(a: int, b: int) -> int:
        return a + b
    
    add("3", 4)  # 实际传入str,与注解的int不符
    
    • mypy 会报错:error: Argument 1 to "add" has incompatible type "str"; expected "int"
类型注解使用场景
01.大型项目或复杂逻辑代码

大型项目代码量大、模块多、调用关系复杂,类型不明确会导致:

  • 开发者难以理解 “某个变量 / 参数到底是什么类型”,增加沟通成本;
  • 容易因类型误用(比如把 strint 运算)引入隐蔽 bug,且调试困难。

示例

一个处理用户数据的函数,参数包含嵌套字典、列表等复杂结构,类型注解能明确每个字段的类型

from typing import List, Dict, Optional

def process_users(users: List[Dict[str, Optional[str | int]]]) -> List[str]:
    """处理用户列表,返回用户名列表"""
    return [user.get("name", "未知") for user in users if isinstance(user.get("name"), str)]
  • 即使隔很久再看代码,也能快速明确 users 是 “元素为字典(键为 str,值可为 str/int/None)的列表”,返回值是 “字符串列表”。
02.团队协作场景

多人协作时,代码需要被其他开发者阅读和调用。类型注解能:

  • 减少 “猜类型” 的时间:无需通读函数实现,通过注解即可知道 “该传什么类型的参数”“会返回什么类型”;
  • 统一代码规范:避免因个人习惯导致的类型理解偏差(比如有人认为参数是 list,有人认为是 tuple)。

示例

团队成员 A 写了一个工具函数,注解清晰时,成员 B 调用时无需询问就能正确传参:

def calculate(a: float, b: float) -> float:
    """计算a和b的乘积"""
    return a * b

# 成员B看到注解,直接传入float类型,无需担心类型错误
result = calculate(3.5, 4.2)
03.函数 / 方法定义时(尤其是公共接口)

函数是代码复用和交互的核心,对函数的参数、返回值加注解,能明确其 “输入输出契约”:

  • 参数多或逻辑复杂的函数:比如接收 10 个参数的工具函数,注解能避免传参时类型混淆;
  • 公共接口 / API:如果你的代码会被其他模块或外部用户调用(比如开发一个库),注解是 “自文档化” 的关键,比文字说明更精确。

示例

一个 Web 框架的接口处理函数,注解明确请求参数和响应类型:

from typing import Dict, Any

def handle_request(params: Dict[str, str], user_id: int) -> Dict[str, Any]:
    """处理用户请求,返回JSON响应"""
    # ... 业务逻辑 ...
    return {"code": 200, "data": f"处理成功,用户ID:{user_id}"}
04.类型容易混淆的场景

当变量 / 参数的类型不直观(比如复合类型、可选类型、动态类型)时,注解能消除歧义:

  • 复合类型:如 list 中的元素类型(list[int] 还是 list[str])、dict 的键值类型(dict[str, User]);
  • 可选类型:变量可能为 None(如 Optional[str] 表示 “字符串或 None”);
  • 联合类型:变量可能是多种类型(如 int | str 表示 “整数或字符串”)。

示例

一个可能返回 “整数或 None” 的函数,注解避免调用者误用:

from typing import Optional

def find_id(name: str) -> Optional[int]:
    """根据名字查找ID,找不到返回None"""
    users = {"Alice": 101, "Bob": 102}
    return users.get(name)

# 调用者看到注解,会知道需要处理None的情况
user_id = find_id("Charlie")
if user_id is not None:
    print(f"ID: {user_id}")  # 避免直接用user_id做运算导致的TypeError
05.重构或维护旧代码时

旧代码往往缺乏注释,类型模糊,重构时容易 “改崩”。此时添加类型注解:

  • 能帮助自己梳理代码逻辑(“这个变量到底是什么类型?”);
  • 配合静态检查工具(如 mypy),自动检测重构后可能出现的类型不匹配问题。

示例

重构一个旧函数时,先补全注解,再用 mypy 检查:

# 旧代码(无注解,逻辑模糊)
def process(data):
    return data * 2

# 重构时补全注解,发现潜在问题
def process(data: int) -> int:
    return data * 2

# 用mypy检查时,若有调用处传入了str(如process("3")),会直接报错
什么时候可以不用?

类型注解是 “辅助工具”,而非 “强制约束”,以下场景可简化或省略:

  • 小型临时脚本:比如几行代码的一次性脚本,类型简单明确,加注解反而增加冗余;
  • 动态性极强的代码:比如使用元编程(evalexec)、动态生成类型的场景,注解难以准确描述,意义不大;
  • 内部临时函数:仅在单个模块内部使用,逻辑简单,且开发者明确类型,可省略。

10.8 多态

在 Python 中,多态(Polymorphism) 是面向对象编程(OOP)的核心特性之一,核心思想是:“同一接口,不同实现”—— 即 不同的对象可以通过相同的方法名(接口)调用,却表现出不同的行为

基本概念

多态的本质是 “灵活性”:当我们操作一个对象时,不需要关心它的具体类型,只需调用它的通用方法,该对象会根据自身类型执行对应的实现。

例如,生活中 “发声” 是一个通用行为(接口):

  • 猫的 “发声” 是 “喵喵叫”;
  • 狗的 “发声” 是 “汪汪叫”;
  • 鸟的 “发声” 是 “叽叽叫”。

我们不需要为每种动物单独定义 “让猫发声”“让狗发声” 的函数,而是用一个通用的 “让动物发声” 的函数,传入不同动物对象时,自动执行对应的行为 —— 这就是多态。

Python 中多态的实现
01.基于继承和方法重写的多态

当子类继承父类并 重写父类的方法 后,通过父类类型的变量(或通用函数)调用该方法时,会根据实际对象的类型执行子类的实现

示例

# 定义一个父类 Animal,包含通用方法 make_sound(),然后让 Cat、Dog 等子类重写该方法:
# 父类:定义通用接口(方法)
# 抽象类(接口)
class Animal:
    # 抽象方法
    def make_sound(self):
        # 父类方法可留空(抽象方法),或提供默认实现
        pass

# 子类1:重写父类方法(具体实现)
class Cat(Animal):
    def make_sound(self):
        print("喵喵叫")

# 子类2:重写父类方法(具体实现)
class Dog(Animal):
    def make_sound(self):
        print("汪汪叫")

# 子类3:重写父类方法(具体实现)
class Bird(Animal):
    def make_sound(self):
        print("叽叽叫")
     
# 定义一个通用函数,接收 Animal 类型的参数并调用 make_sound()
def animal_sound(animal: Animal):  # 注解为Animal类型(通用接口)
    animal.make_sound()  # 调用通用方法,具体行为由实际对象决定
    
cat = Cat()
dog = Dog()
bird = Bird()

animal_sound(cat)   # 输出:喵喵叫(Cat的实现)
animal_sound(dog)   # 输出:汪汪叫(Dog的实现)
animal_sound(bird)  # 输出:叽叽叫(Bird的实现)
  • 抽象类含有抽象方法的类 称之为抽象类,也叫 接口
    • 抽象类设计的含义是:
      • 父类用来确定有哪些方法
      • 具体的方法实现,由子类自行决定
  • 抽象方法方法体是空实现的(pass) 称之为抽象方法
02.基于 “鸭子类型” 的多态

Python 更灵活的是 “鸭子类型(Duck Typing)”:不需要严格的继承关系,只要一个对象 “看起来像鸭子,走起路来像鸭子”(即拥有所需的方法 / 属性),就可以被当作鸭子对待。

简单说:多态不依赖继承,只依赖 “是否实现了相同的方法”

示例

# 有一个 Car 类和 Bicycle 类,它们没有继承关系,但都有 move() 方法
class Car:
    def move(self):
        print("汽车:快速行驶")

class Bicycle:
    def move(self):
        print("自行车:慢慢骑行")
        
# 定义一个通用函数 transport,调用 move() 方法
def transport(vehicle):  # 不限制类型,只要有move()方法即可
    vehicle.move()
    
# 传入 Car 和 Bicycle 实例,都能正常工作
car = Car()
bicycle = Bicycle()

transport(car)      # 输出:汽车:快速行驶
transport(bicycle)  # 输出:自行车:慢慢骑行
  • 这里 CarBicycle 没有继承共同的父类,但因为都实现了 move() 方法,所以可以被 transport 函数统一处理 —— 这是 Python 多态的典型表现

第十一章:编码规范

11.1 下划线

11.1.1 单前导下划线 _func()

在 Python 中,方法名前加单个下划线 _ 是一种 命名约定,它有特定的含义和用途:

表示这是一个 内部方法(internal method),意思是:

  • 仅供类内部使用
  • 不建议从类外部直接调用
  • 不是公共 API 的一部分
11.1.2 单前导下划线 _variable
class MyClass:
    def __init__(self):
        self._internal_data = []  # 内部变量,不建议外部直接访问
11.1.3 单末尾下划线 class_
def function(class_):  # 避免与关键字class冲突
    pass
11.1.4 双前导下划线 __private
class MyClass:
    def __private_method(self):  # 名称修饰(name mangling),有一定保护作用
        pass
11.1.5 双前导和双末尾下划线 __magic__
class MyClass:
    def __init__(self):  # 魔法方法,Python特殊方法
        pass
接下一篇笔记:2025python学习笔记Part2

如有不当之处,欢迎指正

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后藤十八里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值