Python 概述

什么是 Python

Python 它是一种直译式,面向对象,解释式的脚本语言。它和 JavaC/C++Go 语言一样都是高级语言,但由于它是解释式语言,所以运行速度会比 JavaC/C++ 等语言慢。不过任何事物有利也有弊,Python 因为自身携带了许多库(如:OSTCPUrllibTrutle ),语法简单,第三库也有很多,所以被称为胶水语言,同时也深受开发者青眯。

解释型语言,是在运行的时候将程序翻译成机器语言。

解释型语言的程序不需要在运行前编译,在运行程序的时候才翻译,专门的解释器负责在每个语句执行的时候解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。

Python 之父

Python 之父:Guido van Rossum,荷兰人。他也是一个比较传奇的人物,1982年在阿姆斯特丹大学获得计算机和数学科学硕士学位 ,1989年制作 Python,1995年 Guido van Rossum 从荷兰移民到美国,2005年在 Google 工作,并用 Python 发明了面向网页的代码浏览工具 Mondrian,之后又开发了 Rietveld。现在在 Dropbox 工作。

Python 发展史

Python 是一种广受欢迎的高级编程语言,其简洁、优雅、强大的特性使其在各个领域得到广泛应用。从诞生到现在,Python 已经走过了三十多年的发展历程,在这一过程中,Python 不断吸收新的语言特性,完善生态系统,成为了现代软件开发中不可或缺的工具。

  1. Python 的诞生与早期发展

    Python 的创始人是荷兰程序员 Guido van Rossum。1989年圣诞节期间,Guido 有了开发一种新编程语言的想法。他希望这种语言能够简洁、易读、同时具有强大的功能。受到 ABC 语言的启发,Guido 开始着手设计 Python

    1991年,Python 的第一个版本(0.9.0)诞生。这一版本奠定了 Python 语言的基础,包括了类、函数、异常处理等核心特性。

    随后,Python 经历了一系列的迭代和改进。1994年,Python 1.0 发布,标志着 Python 的正式诞生。这一版本引入了 lambdamapfilter 等函数式编程特性,以及对模块和包的支持。

    在早期的发展阶段,Python 主要被用于脚本编写和自动化任务。它简洁的语法和强大的字符串处理能力,使其成为系统管理和文本处理的理想工具。随着 Python 社区的不断壮大,越来越多的开发者开始关注和使用 Python

  2. Python 2.x 时代

    2000年,Python 迎来了一个重要的版本—— Python 2.0。这一版本引入了许多新特性,奠定了 Python 2.x 系列的基础。其中最重要的改进包括:

    • 列表推导式(List Comprehension):提供了一种简洁、优雅的方式来创建列表,大大简化了代码。
    • 垃圾回收机制(Garbage Collection):自动管理内存,减轻了开发者的内存管理负担。
    • Unicode支持:引入了 Unicode 字符串类型,使 Python 能够处理多种语言的文本。
    • 迭代器和生成器(Iterator and Generator):提供了一种高效、灵活的数据处理方式。

    随后的 Python 2.x 版本不断引入新的特性和改进。Python 2.4引入了装饰器(Decorator)和生成器表达式(Generator Expression)。Python 2.5 引入了 with 语句和条件表达式。Python 2.62.7 进一步完善了语言特性和标准库。

    Python 2.x 时代, Python 开始被广泛应用于 Web 开发、科学计算、数据分析、人工智能等领域。诸如 DjangoNumPySciPyMatplotlib 等优秀的第三方库和框架不断涌现,极大地扩展了 Python 的应用范围。

  3. Python 3.x 时代

    2008年,Python 3.0 发布,标志着 Python 进入了一个新的时代。Python 3.x 系列是对 Python 2.x 的一次重大改进和重构,引入了许多新特性和语法改进,同时也做了一些不兼容的改变。 Python 3.x 的主要特性包括:

    • 统一的字符串类型:字符串默认为 Unicode编码,消除了 Python 2.x 中的 Unicode 和字节串之间的混淆。
    • 更加一致的语法:修复了一些语法上的不一致性,使语言更加规范和易于理解。
    • 改进的标准库:对标准库进行了重构和优化,提供了更加高效和便捷的工具。
    • 异步编程支持:引入了 async/await 关键字,使异步编程变得更加简单和直观。
    • 类型注解(Type Annotation):引入了类型注解语法,提高了代码的可读性和可维护性。

    Python 3.x 的发布引发了社区的分化,许多项目和库并没有立即迁移到 Python 3.x。为了缓解这种分化,Python 社区提供了一些工具和策略,如 2to3 转换工具和 six 兼容性库,帮助开发者平滑地过渡到 Python 3.x

    随着时间的推移,越来越多的项目和库开始支持 Python 3.xPython 3.x 逐渐成为主流版本。Python 3.x 的新特性和改进使其成为更加强大、灵活和易用的编程语言。

Python 语言特点

Python 之所以受到广泛欢迎,很大程度上归功于其独特的语言特点。以下是 Python 的一些主要语言特点:

  • 简洁明了的语法:python 采用缩进来表示代码块,减少了括号和分号的使用,使代码更加简洁、易读。
  • 动态类型:Python 是一种动态类型语言,变量的类型在运行时自动推断,无需显式声明。
  • 面向对象:Python 支持面向对象编程范式,具有类、继承、多态等特性。
  • 函数式编程:Python 支持函数式编程特性,如 lambda 函数、高阶函数、闭包等。
  • 丰富的标准库:Python 内置了大量的标准库,涵盖了文件处理、网络编程、数据库访问等各个方面。
  • 强大的第三方生态:Python 拥有海量的第三方库和框架,可以满足各种应用场景的需求。
  • 跨平台支持:Python 可以运行在各种操作系统上,如 WindowsLinuxmacOS 等。
  • 易于扩展:Python 可以与 C/C++ 等语言进行交互,方便地扩展 Python 的功能。

这些语言特点使 Python 成为一种灵活、高效、易学易用的编程语言,适合各种背景的开发者使用。

Python 应用领域

Python 是一种解释型脚本语言,当初设计的目的是编写自动化脚本( Shell ),随着版本的不断更迭和新的语言特性增加,越来越多地被用于独立的大型项目开发,覆盖了 Web 应用开发、数据抓取、科学计算和统计、人工智能与大数据、系统运维、图形界面开发等诸多领域。

  1. Web 应用开发

    Python 包含标准的 Internet 模块,可用于实现网络通信及应用。例如,通过 mod_wsgi 模块,Apache 可以运行用 Python 语言编写的 Web 程序。Python 定义了 wSGI 标准应用接口来协调 HTTP 服务器与基于 PythonWeb 程序之间的通信。Python 的第三方框架,如 DjangoTurboGearsweb2pyZopeFlask 让程序员可以使用 Python 语言快速实现一个网站或 Web 服务,轻松地开发和管理复杂的 Web 程序。目前许多大型网站均是用 Python 开发的,如 Google 爬虫、豆瓣、视频网站 YouTube 、网络文件同步工具 Dropbox 等。

  2. 科学计算和统计

    Python 语言的简洁性、易读性和可扩展性使它被广泛应用于科学计算和统计领域。专用的科学计算扩展库包括 NumPySciPyMatplotlib 等,它们分别为 Python 提供了快速数组处理、数值运算和绘图功能。因此,Python 语言及其众多的扩展库所构成的开发环境十分适合工程技术、科研人员处理实验数据、制作图表、绘制高质量的 2D3D 图像,甚至开发科学计算应用程序。众多开源的科学计算软件包都提供了 Python 的调用接口,例如,著名的计算机视觉库 OpenCV、三维可视化库 VTK、医学图像处理库 ITK 等。

  3. 人工智能和大数据

    在大量数据的基础上,结合科学计算、机器学习等技术,对数据进行清洗、去重、规格化和针对性的分析是大数据行业的基石。随着人工智能、大数据的发展,Python 语言的地位正在逐步提高,其相对简单的代码编写促使越来越多的人选择学习,目前 Python 语言已成为数据分析的主流语言之一。

    Python 语言在人工智能大范畴领域内的机器学习、神经网络、深度学习等方面都是主流的编程语言,得到广泛的支持和应用。基于大数据分析和深度学习发展出来的人工智能本质上已经无法离开 Python 语言的支持,目前世界优秀的人工智能学习框架如 GoogleTensorFlowFacebookPyTorch 和开源社区的神经网络库 Karas 等都是用 Python 语言实现的。微软的 CNTK (认知工具包)也完全支持 Python 语言,而且微软的 VSCode 已经把 Python 语言作为第一级语言进行支持。

  4. 系统运维

    Python 语言是运维工程师首选的编程语言, Python 标准库包含多个调用操作系统功能的库。通过 pywin32 这个第三方软件包,Python 能够访问 WindowsCOM 服务及其他 Windows API。使用 IronPython, Python 程序能够直接调用 .NET Framework

    一般来说,Python 语言编写的系统管理脚本在可读性、性能、代码重用度、扩展性几方面都优于普通的 Shell 脚本。在很多操作系统里,Python 是标准的系统组件。大多数 Linux 发行版以及 NetBSDOpenBSDmacOS X 都集成了 Python,可以在终端下直接运行 Python

    作为运维工程师首选的编程语言,Python 在自动化运维方面已经获得了广泛的应用,如 SaltstackAnsible 都是大名鼎鼎的自动化平台。目前,几乎所有的互联网公司,自动化运维的标准配置就是 Python + Django / Flask。另外,在虚拟化管理方面已经是事实标准的 OpenStack 也是由 Python 实现的。可以说,Python 语言是所有运维人员的必学语言之一。

  5. 图形界面开发

    Python 语言诞生之日起,就有许多优秀的 GUI 工具集整合到 Python 当中,使用 TkinterwxPythonPyQt 库等可以开发跨平台的桌面软件。这些优秀的 GUI 工具集使得 Python 也可以在图形界面编程领域大展身手。由于 Python 语言的流行,许多应用程序都是由 Python 结合那些优秀的 GUI 工具集编写的。

Python 优缺点

优点:免费开源、无社区限制、可开发应用面广、可跨平台、功能强大、自身携带模块多、第三方模块多、语法简单,代码量少可实现多功能等。例如以下代码实例

缺点:运行速度远比 C/C++ 等语言要慢等。

Python 基础环境搭建

在古代战场上,一把趁手的武器与士兵精湛的武术、将军正确的指挥,相辅相成,相得益彰,这样胜率往往会提高很多。这些道理放到配置 Python 解释器方面也同样适用。因此,我们应该如何正确配置 Python 解释器了?下面的方法将会对你正确指导。

Python 安装

官方网站:https://www.python.org/downloads/

image-20240903102333312

点击这里下载,也可以在下图中选择合适的版本和系统:

image-20240903102507424

选择合适的系统下载:

image-20240903102724441

安装没什么好说的,正常一路下一步即可。

注意:不要安装到中文目录下,不要安装到带有空格的目录下。一般我在 D盘 下创建一个文件夹 soft ,软件都在这个文件夹下。

安装好后,打开控制台,输入

python3 --version

如果出现以下画面就代表安装完毕:

image-20240903103537691

PyCharm 安装

官方网站:https://www.jetbrains.com/zh-cn/pycharm/

image-20240903104038749

进入详情页面,下载对应系统对应版本的软件即可。

image-20240903104244590

下载完成后,正常安装即可,没什么特别要说的。

注意:不要安装到中文目录下,不要安装到带有空格的目录下。一般我在 D盘 下创建一个文件夹 soft ,软件都在这个文件夹下。

Hello,world!

创建项目

image-20240903112902032

环境选择

image-20240903114632038

PyCharm 中不同解释器选项,包括 ProjectvenvBaseCondaCustomenvironment 的使用场景。

  • Project venv:当前项目的虚拟环境,python 版本可以在右侧小箭头下拉选择,在当前项目内安装的包只会在项目内有效。

  • Base CondaAnaconda 环境,Anaconda 是一个集成了大量 python 包的 python 环境,如果选择这个需要先在电脑内安装Anaconda

  • Custom environment :自定义环境,可以指定一个已经存在的 python 环境或者让 pycharm 下载一个新的,自定义环境可以同时作为其他项目的环境。

    • generate new 新建虚拟环境(选择本机已安装的 python 或下载新的 python 作为 BasePythongenerate new 表示为新项目基于你所选择虚拟环境中的 python 作为 Base python 生成一个虚拟环境,生成后放在其项目文件夹下的 venv 中,使用 venv 作为编译器。

      这里所选择的虚拟环境中已安装的第三方库并不会出现在新生成的项目下的 venv 中,可以说只是将已安装的虚拟环境下的 python 复制了一份到项目下的 venv 中,所有需要使用的第三方库都需要重新安装。它可以脱离系统安装的 python 独立运行,它对于自身 venv 的修改也只影响它自身。当然它的基础虚拟环境是基于 Base python 进行建立的,所以使用 conda 在其 Basepython 中安装第三官方库对这里新建的项目环境没有影响。

    • Select existing 选择已配置好的虚拟环境 Select existing 表示选择已安装的虚拟环境作为自己的编译器,并不会在项目文件夹下产生项目本身的 venv,所选择的虚拟环境中的所有已安装的第三方包都可以使用,而不用重新安装。

入门案例中,我们使用第一种方式创建项目。

创建包和类

项目下新建包(Python 软件包),在该包下新建类

image-20240903143024293

Python 类的后缀为 .py

书写代码

print('Hello,world!');

运行效果

image-20240903143319562

书写注释

Python 中的注释是向代码添加说明的文本,它们不会被解释器执行,但对于理解代码非常有帮助。

如何添加注释:

  • 单行注释:使用井号 #,后面跟注释文本。
  • 多行注释:使用三对引号 """''',其中间是多行注释。
# 我是单行注释
"""
我是多行注释
"""

注意:一般多行注释我们推荐使用 """ 方式完成。

包和模块

无论是库、包、模块,其核心都在于封装了一系列的功能。

  • library,这个概念并非 Python 里的概念,是从 C 语言过来的。库这个概念其实就是一堆代码一起完成一个或多个任务。非常类似函数,但是是以文件组织在一起。库是模块和包的集合,提供特定功能(如数据处理、Web 开发)。
  • 模块 module,这个概念就是 Python 里的概念,一个模块就是一个 py 文件,然后包含多行代码执行一个或多个任务。
  • package。包含多个模块的目录为包 package,通俗来说包就是一类功能模块的组织者。

模块

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在 Python 中,一个 .py 文件就称之为一个模块(Module)。

模块是一个包含所有定义的函数和变量的文件,其后缀名是 .py。模块可以被别的程序引入,以使用该模块中的函数等功能。

最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括 Python 内置的模块和来自第三方的模块。

使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。但是也要注意,尽量不要与内置函数名字冲突。

但是如果不同的人编写的模块名相同怎么办,为了避免模块名冲突,Python 又引入了按目录来组织模块的方法,称为包(Package)。

包是一种管理 Python 模块命名空间的形式,采用点模块名称。比如一个模块的名称是 A.B, 那么表示一个包 A 中的子模块 B 。就好像使用模块的时候,不用担心不同模块之间的全局变量相互影响一样,采用点模块名称这种形式也不用担心不同库之间的模块重名的情况。

包就可以看成是文件夹,传统包里有一个 __init__.py 文件。可以为空文件,但一定要有该文件,它是包的标志性文件,否则,Python就把这个目录当成普通目录,而不是一个包。在需要情况下可以在里面进行一些包的初始化工作。

import 语句

import

想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:

import module1[, module2[,... moduleN]

当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。搜索路径时一个解释器会先进行搜索的所有目录的列表。

一个模块只会被导入一次,不管你执行了多少次 import。这样可以防止导入模块被一遍又一遍地执行。

from import

Pythonfrom 语句可以从模块中导入一个指定的部分到当前命名空间中。语法如下:

from modname import name1[, name2[, ... nameN]]

如果说 import 是导入整个模块,那么 from import 就是导入模块中的部分内容(函数)。例如:

from DemoA import method_a

这个声明不会把整个 DemoA 模块导入到当前的命名空间中,它只会将 DemoA 里的 method_a 函数引入进来。

from import *

把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:

from modname import *

这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。

变量和运算符

变量

任何编程语言都需要处理数据,比如数字、字符串、字符等,我们可以直接使用数据,也可以将数据保存到变量中,方便以后使用。

变量(Variable)可以看成一个小箱子,专门用来盛装程序中的数据。每个变量都拥有独一无二的名字,通过变量的名字就能找到变量中的数据。从底层看,程序中的数据最终都要放到内存(内存条)中,变量其实就是这块内存的名字。

和变量相对应的是常量(Constant),它们都是用来盛装数据的小箱子,不同的是:变量保存的数据可以被多次修改,而常量一旦保存某个数据之后就不能修改了。

变量的定义

Python 中定义变量非常简单:

变量名 = 值

这段代码的意思是:将赋予变量

例如:

age = 19
print(age)

输出的效果是:

image-20240903145240536

变量的命名

  • 命名规则(一定要遵守)
    • 变量名由数字、字母、中文和下划线构成。
    • 数字不能开头。
    • 变量名不能和关键字重复。
    • 变量名区分大小写。numNum 是两个不同的变量名。
  • 命名规范 (建议遵守)
    • 尽量不要使用中文。
    • 变量名使用有描述性的单词来表示,尽量表达出变量的作用。
    • 一个变量名可以由多个单词构成,长一点没关系,但是要求含义清晰。
    • 当变量名包含多个单词的时候,建议使用”驼峰命名法”或者”蛇形命名法”。

驼峰命名:除了第一个单词的首字母以外,后续每个单词的首字母都大写。

例如:personInfo , totalCount

蛇形命名:单词之间,使用下划线_来进行分隔。

例如:person_info , total_count

Pep8 风格指南

除了上述基本规则外,Python 还有一个名为 Pep8 的编码规范。它提供了关于命名规则的更多建议,例如:

  • 使用小写字母和下划线命名变量和函数,如 my_variablemy_function

  • 使用驼峰式命名法命名类,如 MyClass

  • 使用全大写字母命名常量,如 MY_CONSTANT

变量的使用

a = 19
print(a)
a = 25
print(a)

首次使用 =a 设置值,这个过程是创建变量并第一次赋值,也称为初始化

后续使用 =a 设置值,相当于修改 a 的内容,称为赋值

注意,变量的值一旦被修改,之前的值就被覆盖了,不复存在了,再也找不回了。换句话说,变量只能容纳一个值。

批量赋值

a,b = 20,'abc'

也可以使用上述代码方式批量给多个变量赋值。

变量的数据类型

Python弱类型的语言,在强类型的编程语言中,定义变量时要指明变量的数据类型,而且赋值的数据也必须是相同类型的,C语言C++Java 是强类型语言的代表。

和强类型语言相对应的是弱类型语言,PythonJavaScriptPHP 等脚本语言一般都是弱类型的。

弱类型语言有两个特点:

  1. 变量无须声明就可以直接赋值,对一个不存在的变量赋值就相当于定义了一个新变量。
  2. 变量的数据类型可以随时改变,比如,同一个变量可以一会儿被赋值为整数,一会儿被赋值为字符串。

注意,弱类型并不等于没有类型!弱类型是说在书写代码时不用刻意关注类型,但是在编程语言的内部仍然是有类型的。我们可以使用 type() 内置函数类检测某个变量或者表达式的类型,例如:

age = 19
name = "张三"
gender = '男'
print(age, name, gender)
print(type(age), type(name), type(gender))

运行结果:

image-20240903152129512
整数类型

整数就是没有小数部分的数字,Python 中的整数包括正整数0负整数

有些强类型的编程语言会提供多种整数类型,每种类型的长度都不同,能容纳的整数的大小也不同,开发者要根据实际数字的大小选用不同的类型。例如 java 提供了 byteshortint、和 long 四种类型的整数,它们的长度依次递增,初学者在选择整数类型时往往比较迷惑,有时候还会导致数值溢出。

Python 则不同,它的整数不分类型,或者说它只有一种类型的整数Python 整数的取值范围是无限的,不管多大或者多小的数字,Python 都能轻松处理。

当所用数值超过计算机自身的计算能力时,Python 会自动转用高精度计算(大数计算)。例如如下代码:

num = 19
print(num)
num = 98789878987658
print(num)
num = -823827482832382
print(num)

运行结果:

image-20240903154000648

num 可以是一个极大的数字,也可以是一个很小的数字,Python 都能正确输出,不会发生溢出,这说明 Python 对整数的处理能力非常强大。

不管对于多大或者多小的整数,Python3 只用一种类型存储,那就是 int

整数的不同进制

Python 中,可以使用多种进制来表示整数:

  1. 十进制形式 我们平时常见的整数就是十进制形式,它由 0~9 共十个数字排列组合而成。注意,使用十进制形式的整数不能以 0 作为开头,除非这个数值本身就是 0。

  2. 二进制形式 由 0 和 1 两个数字组成,书写时以 0b0B 开头。例如,101 对应十进制数是 5。

  3. 八进制形式 八进制整数由 0~7 共八个数字组成,以 0o0O 开头。注意,第一个符号是数字 ,第二个符号是大写或小写的字母 O

  4. 十六进制形式 由 0~9 十个数字以及 A~F(或 a~f)六个字母组成,书写时以 0x0X 开头。

# 十六进制
hex1 = 0x45
hex2 = 0x4Af
print("hex1Value: ", hex1)
print("hex2Value: ", hex2)
# 二进制
bin1 = 0b101
bin2 = 0B110
print('bin1Value: ', bin1)
print('bin2Value: ', bin2)
# 八进制
oct1 = 0o26
oct2 = 0O41
print('oct1Value: ', oct1)
print('oct2Value: ', oct2)
浮点数类型

在编程语言中,小数通常以浮点数的形式存储。浮点数和定点数是相对的:小数在存储过程中如果小数点发生移动,就称为浮点数;如果小数点不动,就称为定点数。

Python 中的小数有两种书写形式:

  • 十进制形式

    这种就是我们平时看到的小数形式,例如 34.6、346.0、0.346。

    书写小数时必须包含一个小数点,否则会被 Python 当作整数处理。

  • 指数形式

    Python 小数的指数形式的写法为:

    aEn 或 aen

    a 为尾数部分,是一个十进制数;n 为指数部分,是一个十进制整数;Ee 是固定的字符,用于分割尾数部分和指数部分。

    整个表达式等价于 $$ a*10^n $$

Python 只有一种小数类型,就是 float

Java 有两种小数类型,分别是 floatdoublefloat 能容纳的小数范围比较小,double 能容纳的小数范围比较大。

浮点数的精度问题

前面提到,Python 中浮点类型之间的运算,其结果并不像我们想象的那样,例如:

print(0.1 + 0.2)
print(0.1 + 0.1 - 0.2)
print(0.1 + 0.1 + 0.1 - 0.3)
print(0.1 + 0.1 + 0.1 - 0.2)

结果如下:

image-20240904113142924

为什么在计算这么简单的问题上,计算机会出现这样的低级错误呢?真正的原因在于十进制和数和二进制数的转换。

我们知道,计算机其实是不认识十进制数,它只认识二进制数,也就是说,当我们以十进制数进行运算的时候,计算机需要将各个十进制数转换成二进制数,然后进行二进制间的计算。

以类似 0.1 这样的浮点数为例,如果手动将其转换成二进制,其结果为:

0.1(10) = 0.00011001100110011…(2)

可以看到,结果是无限循环的,也就是说,0.1 转换成二进制数后,无法精确到等于十进制数的 0.1。同时,由于计算机存储的位数是有限制的,所以如果要存储的二进制位数超过了计算机存储位数的最大值,其后续位数会被舍弃,舍弃的原则是 0 舍 1 入

注意:这种问题不仅在 Python 中存在,在所有支持浮点数运算的编程语言中都会遇到,它不光是 PythonBug

明白了问题产生的原因之后,那么该如何解决呢?就 Python 的浮点数运算而言,大多数计算机每次计算误差不会超过 253,这对于大多数任务来说已经足够了。

如果需要非常精确的结果,可以使用 decimal 模块,它实现的十进制数运算适合会计方面的应用和有高精度要求的应用。例如:

# 使用模块前,需要使用 import 引入
import decimal

a = decimal.Decimal("0.1")
b = decimal.Decimal("0.2")
print(a + b)
print(a + a - b)
print(a + a + a - b)
print(a + a + a - b)

我们再来看看结果:

image-20240904113736197

可以看到,相比普通运算的结果,使用 decimal 模块得到的结果更精确。

数字分隔符

为了提高数字的的可读性,Python 3.x 允许使用下划线 _ 作为数字(包括整数和小数)的分隔符。通常每隔三个数字添加一个下划线,类似于英文数字中的逗号。下划线不会影响数字本身的值。

pi = 3.141_592_652
distance = 384_000_000
print("圆周率是:", pi)
print("地球和月球的距离:", distance)

运行结果:

image-20240903161505976
布尔类型

Python 提供了 bool 类型来表示,比如常见的 5 > 3 比较算式,这个是正确的,在程序世界里称之为真,Python 使用 True 来代表;再比如 4 > 20 比较算式,这个是错误的,在程序世界里称之为假,Python 使用 False 来代表。

TrueFalsePython 中的关键字,当作为 Python 代码输入时,一定要注意字母的大小写,否则解释器会报错。

值得一提的是,布尔类型可以当做整数来对待,即 True 相当于整数值 1,False 相当于整数值 0。因此,下边这些运算都是可以的:

print(True + 1)
print(False - 3)

结果是:

image-20240903165312956

注意,这里只是为了说明 TrueFlase 对应的整型值,在实际应用中是不妥的,不要这么用。

总的来说,bool 类型就是用于代表某个事情的真或假,如果这个事情是正确的,用 True(或 1)代表;如果这个事情是错误的,用 False(或 0)代表。

复数类型

复数(Complex)是 Python 的内置类型,直接书写即可。换句话说,Python 语言本身就支持复数,而不依赖于标准库或者第三方库。

复数由实部(real)和虚部(imag)构成,在 pythoni 被挪着它用,虚数单位是不区分大小写的 J。复数的虚部以 j 或者 J 作为后缀,具体格式为:

a + bj
## 或者
complex(a, b)

其中,a 表示实部,b 表示虚部。

image-20240903162707601

复数,是数的概念扩展。我们把形如 z=a+bjab 均为实数)的数称为复数。其中,a 称为实部,b 称为虚部,j 称为虚数单位。当 z 的虚部 b=0 时,则 z 为实数;当 z 的虚部 b≠0 时,实部 a=0 时,常称 z 为纯虚数。复数域是实数域的代数闭包,即任何复系数多项式在复数域中总有根。

字符串类型

若干个字符的集合就是一个字符串(String),它是个不可变的字符序列。Python 中的字符串必须由双引号” “或者单引号’ ‘包围,具体格式为:

"字符串内容"
'字符串内容'

字符串的内容可以包含字母、标点、特殊符号、中文等全世界的所有文字。Python 字符串中的双引号和单引号没有任何区别。

字符串中的一些函数:

函数 说明 案例
len() 返回字符串的长度 size=’abcd’.len()
lower() 返回字符串的小写形式 s1=’AbCd’.lower()
upper() 返回字符串的大写形式 s2=’AbCd’.upper()
capitalize() 将字符串的第一个字符转换为大写,并返回新字符串 s3=’Hello,world’.capitalize()
strip() lstrip() rstrip() 去除字符串两端、左端或右端的空格或指定字符 str = ” Hello, World “

print(str.strip()) # 输出:”Hello, World”
print(str.lstrip()) # 输出:”Hello, World “
print(str.rstrip()) # 输出:” Hello, World”
find() index() 查找子字符串在字符串中的位置 str = ” Hello, World “

print(str.find(“World”)) # 输出:10
print(str.index(“World”)) # 输出:10
replace() 替换字符串中的子字符串 str = “Hello, World”

print(str.replace(“World”,”Hello”)) # 输出:Hello, Hello
center() 将字符串居中,并使用指定字符(默认为空格)填充两侧的空白部分,使得字符串长度为指定宽度,并返回新字符串。需要注意的是,指定字符有且仅为1位。 str = “Hello,World”
print(str.center(20,’-‘)) # 输出:—-Hello,World—–
isupper() islower() 判断字符串中所有字母是否都是大写或者小写,并返回相应的布尔值。 str = “Hello,World”
print(str.isupper()) # 输出:False
print(str.islower()) # 输出:False

Python 中有一些特殊的字符串需要注意:

  1. 长字符串

    Python 中,使用三个单引号或者双引号可以对多行内容进行注释,这其实是 Python 长字符串的写法。所谓长字符串,就是可以直接换行书写的字符串。

    ## 长字符串中的换行、空格、缩进等空白符都会原样输出
    message = '''白日依山尽 黄河入海流
    欲穷千里目 更上一层楼'''
    print(message)

    效果如下:

    image-20240903172720318

    当程序中有大段文本内容需要定义成字符串时,优先推荐使用长字符串形式,因为这种形式非常强大,可以在字符串中放置任何内容,包括单引号和双引号。

  2. 特殊字符串

    当字符串内容中出现引号时,我们需要进行特殊处理,否则 Python 会解析出错,例如:

    message = 'I'm Lili,How are you?'
    print(message)

    由于上面字符串中包含了单引号,此时 Python 会将字符串中的单引号与第一个单引号配对,这样就会把 'I' 当成字符串,而后面的 m Lili,How are you?' 就变成了多余的内容,从而导致语法错误。这里我们就需要使用转义字符来处理:

    message = 'I\'m Lili,How are you?'
    print(message)
  3. 字符串换行

    如果不使用长字符串的情况下,我们的内容不会原样输出,这时候我们需要换行就需要使用到 \n来完成。

    message = '白日依山尽 黄河入海流\n欲穷千里目 更上一层楼'
    print(message)
  4. 原始字符串

    Python 字符串中的反斜杠 \ 有着特殊的作用,就是转义字符,例如上面提到的换行、\’ 和 \”。

    但是转义字符有时候会带来一些麻烦,例如我要表示一个包含 Windows 路径 D:\soft\Python\python.exe 这样的字符串,在 Python 程序中直接这样写肯定是不行的,不管是普通字符串还是长字符串。因为 \ 的特殊性,我们需要对字符串中的每个 \ 都进行转义,也就是写成如下形式:

    message = 'D:\\soft\\Python\\python.exe'

    这种写法需要特别谨慎,稍有疏忽就会出错。为了解决转义字符的问题,Python 支持原始字符串。在原始字符串中,\ 不会被当作转义字符,所有的内容都保持“原汁原味”的样子。

    在普通字符串或者长字符串的开头加上 r 前缀,就变成了原始字符串,具体格式为:

    str1 = r'原始字符串内容'
    str2 = r"原始字符串内容"

    例如刚才的写法:

    message = r'D:\soft\Python\python.exe'

    注意:转义字符中的 \’ 和 \” 在原始字符串中仍然需要通过 \'\" 转义。

bytes 类型

Python bytes 类型用来表示一个字节串。字节串不是编程术语,是大家约定俗成的一个词,用来和字符串相呼应。

bytesPython 3.x 新增的类型,在 Python 2.x 中是不存在的。

字节串(bytes)和字符串(string)的对比:

  • 字符串由若干个字符组成,以字符为单位进行操作;字节串由若干个字节组成,以字节为单位进行操作。
  • 字节串和字符串除了操作的数据单元不同之外,它们支持的所有方法都基本相同。
  • 字节串和字符串都是不可变序列,不能随意增加和删除数据。

bytes 只负责以字节序列的形式(二进制形式)来存储数据,至于这些数据到底表示什么内容(字符串、数字、图片、音频等),完全由程序的解析方式决定。如果采用合适的字符编码方式(字符集),字节串可以恢复成字符串;反之亦然,字符串也可以转换成字节串。

说白了,bytes 只是简单地记录内存中的原始数据,至于如何使用这些数据,bytes 并不在意,你想怎么使用就怎么使用,bytes 并不约束你的行为。

bytes 类型的数据非常适合在互联网上传输,可以用于网络通信编程;bytes 也可以用来存储图片、音频、视频等二进制格式的文件。

字符串和 bytes 存在着千丝万缕的联系,我们可以通过字符串来创建 bytes 对象,或者说将字符串转换成 bytes 对象。有以下三种方法可以达到这个目的:

  1. 如果字符串的内容都是 ASCII 字符,那么直接在字符串前面添加 b 前缀就可以转换成 bytes
  2. bytes 是一个类,调用它的构造方法,也就是 bytes(),可以将字符串按照指定的字符集转换成 bytes;如果不指定字符集,那么默认采用 UTF-8
  3. 字符串本身有一个 encode() 方法,该方法专门用来将字符串按照指定的字符集转换成对应的字节串;如果不指定字符集,那么默认采用 UTF-8

例如如下代码:

b1 = b'Hello,world!'
b2 = bytes('Hello,world!', 'utf-8')
message = 'Hello,world!'
b3 = message.encode('utf-8')
print('b1`type:', type(b1), ",b1:", b1)
print('b2`type:', type(b2), ",b2:", b2)
print('b3`type:', type(b3), ",b3:", b3)

运行结果是:

image-20240904094543586

bytes 类也有一个 decode() 方法,通过该方法可以将 bytes 对象转换为字符串。

str1 = b3.decode('utf-8')

类型转换

虽然 Python 是弱类型编程语言,不需要像 Java 那样还要在使用变量前声明变量的类型,但在特定场景中,仍然需要用到类型转换。

比如说如下代码:

weight = 166.8
print('你的体重是:' + weight)

就会出现:

image-20240904110351994

你会发现这是错误的,解释器提示我们字符串和浮点类型变量不能直接相连,需要提前将浮点类型变量 weight 转换为字符串才可以。

庆幸的是,Python 已经为我们提供了多种可实现数据类型转换的函数,如下所示:

函 数 作 用
int(x) x 转换成整数类型
float(x) x 转换成浮点数类型
complex(real,[,imag]) 创建一个复数
str(x) x 转换为字符串
repr(x) x 转换为表达式字符串
eval(str) 计算在字符串中的有效 Python 表达式,并返回一个对象
chr(x) 将整数 x 转换为一个字符
ord(x) 将一个字符 x 转换为它对应的整数值
hex(x) 将一个整数 x 转换为一个十六进制字符串
oct(x) 将一个整数 x 转换为一个八进制的字符串

在来看看刚才的代码:

weight = 166.8
# 这样书写是错误的 因为 weight 不是整数
# print('你的体重是:' + chr(weight))
# 应该这样书写
print('你的体重是:' + str(weight))
image-20240904110856093

转义字符

在前边的章节中我们曾提到过转义字符,就是那些以反斜杠 \ 开头的字符。

ASCII 编码为每个字符都分配了唯一的编号,称为编码值。在 Python 中,一个 ASCII 字符除了可以用它的实体(也就是真正的字符)表示,还可以用它的编码值表示。这种使用编码值来间接地表示字符的方式称为转义字符(Escape Character)。

转义字符以 \0 或者 \x 开头,以 \0 开头表示后跟八进制形式的编码值,以 \x 开头表示后跟十六进制形式的编码值,Python 中的转义字符只能使用八进制或者十六进制。具体格式如下:

\0dd
\xhh

dd 表示八进制数字,hh 表示十六进制数字。

ASCII 编码共收录了 128 个字符,\0\x 后面最多只能跟两位数字,所以八进制形式 \0 并不能表示所有的 ASCII 字符,只有十六进制形式 \x 才能表示所有 ASCII 字符。

我们一直在说 ASCII 编码,没有提及 UnicodeGBKBig5 等其它编码(字符集),是因为 Python 转义字符只对 ASCII 编码(128 个字符)有效,超出范围的行为是不确定的。

字符 123xyz 对应的 ASCII 码的八进制形式分别是 616263170171172,十六进制形式分别是 31323378797A

注意:使用八进制形式的转义字符没法表示 xyz,因为它们的编码值转换成八进制以后有三位。

对于 ASCII 编码,0~31(十进制)范围内的字符为控制字符,它们都是看不见的,不能在显示器上显示,甚至无法从键盘输入,只能用转义字符的形式来表示。不过,直接使用 ASCII 码记忆不方便,也不容易理解,所以,针对常用的控制字符,C语言 又定义了简写方式,完整的列表如下:

转义字符 说明
\n 换行符,将光标位置移到下一行开头。
\r 回车符,将光标位置移到本行开头。
\t 水平制表符,也即 Tab 键,一般相当于四个空格。
\a 蜂鸣器响铃。注意不是喇叭发声,现在的计算机很多都不带蜂鸣器了,所以响铃不一定有效。
\b 退格(Backspace),将光标位置移到前一列。
\ 反斜线
单引号
" 双引号
\ 在字符串行尾的续行符,即一行未完,转到下一行继续写。

转义字符在书写形式上由多个字符组成,但 Python 将它们看作是一个整体,表示一个字符。

运算符

本节主要介绍 Python 中的各种运算符,包括算术运算符(如加、减、乘、除等)、比较运算符、赋值运算符、逻辑运算符、位运算符、成员运算符和身份运算符,以及运算符的优先级规则,为初学者提供了全面的基础知识。

随机数

为了便于演示方便,这里我们引入 python 随机数来进行变量赋值。

import random
num1 = random.randint(a, b) # 获取a到b之间的一个随机整数
num2 = random.random() # 获取一个[0,1)之间的一个随机浮点数
num3 = random.uniform(a,b) # 获取a到b之间的一个随机浮点数
函数 说明 示例
randint(a, b) 生成 [a, b] 之间的整数(包含 a 和 b) random.randint(1, 6) 模拟掷骰子
randrange(start, stop[, step]) 类似 range(),生成 [start, stop) 之间的整数(不包含 stop) random.randrange(0, 10, 2) 随机选偶数

算术运算符

算术运算符也即数学运算符,用来对数字进行数学运算,比如加减乘除。下表列出了 Python 支持所有基本算术运算符。

假设:a 的值是 10b 的值是 20

运算符 描述 实例
+ 加 – 两个对象相加 a + b 输出结果 30
减 – 得到负数或是一个数减去另一个数 a - b 输出结果 -10
* 乘 – 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200
/ 除 – x 除以 y b / a 输出结果 2
// 取整除 – 返回商的整数部分(向下取整 b // a 输出结果 2
8 // 3 输出结果 2
% 取模 – 返回除法的余数 b % a 输出结果 0
** 幂 – 返回 xy 次幂 a**b 为 10 的 20 次方, 输出结果 100000000000000000000

比较运算符

比较运算符也叫关系运算符,用来比较表达式之间的关系,或得到的结果是 True 或者 False

假设:a 的值是 10b 的值是 20

运算符 描述 实例
== 等于 – 比较对象是否相等 (a == b) 返回 False
!= 不等于 – 比较两个对象是否不相等 (a != b) 返回 True
不等于 – 比较两个对象是否不相等。python3 已废弃。 (a <> b) 返回 True
这个运算符类似 != 。
> 大于 – 返回 x 是否大于 y (a > b) 返回 False
< 小于 – 返回 x 是否小于 y (a < b) 返回 True
>= 大于等于 – 返回 x 是否大于等于 y (a >= b) 返回 False
<= 小于等于 – 返回 x 是否小于等于 y (a <= b) 返回 True

注意:所有比较运算符返回 1 表示真,返回 表示假。这分别与特殊的变量 TrueFalse 等价。

赋值运算符

作用是将等号右边的值赋予等号左边的变量。

假设:a 的值是 10b 的值是 20

运算符 描述 实例
= 简单的赋值运算符 c = a + ba + b 的运算结果赋值为 c
+= 加法赋值运算符 c += a 等效于 c = c + a
-= 减法赋值运算符 c -= a 等效于 c = c - a
*= 乘法赋值运算符 c *= a 等效于 c = c * a
/= 除法赋值运算符 c /= a 等效于 c = c / a
%= 取模赋值运算符 c %= a 等效于 c = c % a
**= 幂赋值运算符 c **= a 等效于 c = c ** a
//= 取整除赋值运算符 c //= a 等效于 c = c // a

注意:python 中不存在 a++ 或者 ++a 的写法。

逻辑运算符

在中国工作的年龄是有限制范围的,大于18岁且小于60岁,那么如果我想要写这2个年龄限制条件,一个是大于等于18,一个是小于等于60,怎么把这两个条件连接到一起呢,这时候想要连接着2个扩充条件就要用到逻辑运算符了。

假设:a 的值是 10b 的值是 20

运算符 逻辑表达式 描述 实例
and x and y 布尔”与” – 如果 xFalsex and y 返回 False,否则它返回 y 的计算值。 (a and b) 返回 20。
or x or y 布尔”或” – 如果 x 是非 0,它返回 x 的计算值,否则它返回 y 的计算值。 (a or b) 返回 10。
not not x 布尔”非” – 如果 xTrue,返回 False 。如果 xFalse,它返回 True not(a and b) 返回 False
a, b, c = 1, 2, 3
# 1. and: 与 都真才真
print(a < b and b < c)  # True
print(a < b and b > c)  # False
print(a and b)  # a 不是 True 则返回 b 的值

# 2. or: 或 一真则真,都假才假
print(a > b or b < c)  # True
print(a > b or b > c)  # False
print(a or b)  # a 是非0 则返回 a 的值

# 3. not: 非 取反
print(not False)  # True
print(not c > b)  # False

注意:一般来讲,逻辑运算符主要应用于多个条件的拼接,得到的结果一般都是 True 或者 False

位运算符

按位运算符是把数字看作二进制来进行计算的。Python 中的按位运算法则如下:

假设:a 的值是 10b 的值是 20。二进制格式如下:

a = 0000 1010

b = 0001 0100

-----------------

a&b = 0000 0000

a|b = 0001 1110

a^b = 0001 1110

~a  = 1111 0101(补码形式)
运算符 描述 实例
& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 0 ,二进制解释:0000 0000
| 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1 (a | b) 输出结果 30 ,二进制解释:0001 1110
^ 按位异或运算符:当两对应的二进位相异时,结果为1 (a ^ b) 输出结果 30 ,二进制解释:0001 1110
~ 按位取反运算符:将二进制表示中的每一位取反,0 变为 1,1 变为 0。 (~a ) 输出结果 -11 ,二进制解释: 1111 0101 (以补码形式表示),在一个有符号二进制数的补码形式。
<< 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0。 a << 2 输出结果 40 ,二进制解释: 0010 1000
>> 右移动运算符:把”>>”左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数 a >> 2 输出结果 2 ,二进制解释: 0000 0010

原码、反码和补码

在学习原码,反码和补码之前, 需要先了解机器数和真值的概念。

  1. 机器数

    一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用机器数的最高位存放符号,正数为0,负数为1。

    比如,十进制中的数 +3 ,计算机字长为 8 位,转换成二进制就是 0000 0011。如果是 -3 ,就是 100 00011 。那么,这里的 0000 00111000 0011 就是机器数。

  2. 机器数的真值

    因为第一位是符号位,所以机器数的形式值就不等于真正的数值。

    例如上面的有符号数 1000 0011,其最高位 1 代表负,其真正数值是 -3,而不是形式值 131(1000 0011 转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。

    例:0000 0001 的真值 = +000 0001 = +1,1000 0001 的真值 = –000 0001 = –1。

下来我们来聊一聊原码,反码和补码:

  1. 原码

    原码是机器数的一种表示方法。在原码表示中,最高位表示符号位,0 表示正数,1 表示负数,其余位表示数值的绝对值。

    例如,对于 8 位二进制数:

    • 正数 5 的原码是 0000 0101 ,其中最高位 0 表示正数,后面 7 位 0000101 表示数值 5 。
    • 负数 -5 的原码是 1000 0101 ,最高位 1 表示负数,后面 7 位 0000101 表示数值 5 。

    原码的优点是直观易懂,与人的日常习惯比较接近。

    但在进行加减法运算时,需要单独处理符号位,比较复杂。比如计算 5 + (-5) ,用原码计算时,先分别写出 5 和 -5 的原码 0000010110000101 ,然后进行加法运算,得到 10001010 ,其结果是 -10 ,这显然是错误的。这就体现出原码在进行运算时的不便,所以在计算机中,更多使用补码来进行运算。

  2. 反码

    反码也是机器数的一种表示方式。对于正数,其反码与原码相同;对于负数,其反码是在原码的基础上,符号位不变,其余各位取反。

    例如,对于 8 位二进制数:

    • 正数 7 的原码和反码都是 00000111
    • 负数 -7 的原码是 10000111 ,反码则是 11111000

    反码的出现主要是为了在计算机运算中解决原码运算的一些问题,但它本身在运算中也存在一定的局限性。比如计算 -7 + 7 ,先写出 -7 的反码 11111000 ,7 的反码 00000111 ,相加得到 1 1111111 ,结果是 -127,并不是 0 。

    所以,反码在实际计算机运算中使用较少,更多地是作为理解补码的一个过渡概念。

  3. 补码

    补码是计算机中一种重要的机器数表示方法。对于正数,其补码与原码相同;对于负数,其补码是在反码的基础上加 1 。

    例如,对于 8 位二进制数:

    • 正数 4 的原码、反码和补码都是 0000 0100
    • 负数 -4 ,原码是 1000 0100 ,反码是 1111 1011 ,补码则是 1111 1100

    补码的优点在于可以将减法运算转换为加法运算,简化了计算机的运算逻辑。比如计算 5 – 3 ,可以转化为 5 + (-3) 。5 的补码是 0000 0101 , -3 的补码是 1111 1101 ,两者相加得到 0000 0010 ,结果为 2 ,计算过程简单高效。在计算机的存储和运算中,广泛使用补码来表示有符号数,极大地提高了运算的效率和准确性。

成员运算符

除了以上的一些运算符之外,Python 还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。

运算符 描述 实例
in 如果在指定的序列中找到值返回 True,否则返回 False xy 序列中返回 True
not in 如果在指定的序列中没有找到值返回 True,否则返回 False x 不在 y 序列中返回 True
from random import random
# 获取到 1-10 的一个随机整数
x = random.randint(1, 10)
y = [1, 3, 5, 7, 9]
print('x的值是:', x)
# 如果 x 是奇数则返回 `True`,否则返回 `False`
print('是否在:', y, '序列中?', x in y)
print('是否不在:', y, '序列中?', x not in y)

身份运算符

用于比较两个对象的内存地址。 Python 中的身份运算符包括:isis not

运算符 描述
is is 是判断两个标识符是不是引用自一个对象
is not is not 是判断两个标识符是不是引用自不同对象

== 和 is 之间的区别

is 用于判断两个变量引用对象是否为同一个(同一块内存空间), == 用于判断引用变量的值是否相等。

a = [1, 2, 3, 4]
b = [1, 2, 3, 4]
print(a == b) # True
print(a is b) # False

输入和输出

输入可以获取用户的数据,输出可以展示程序运行的结果。通过输入和输出,用户和程序就可以进行交互,程序根据用户的输入展示输出。在 Python 中使用 input 函数进行输入,使用 print 函数进行输出。

输出操作

对于输出,在 Python 中,我们有多种方式去实现:表达式输出、print 函数输出以及文件输出。这里我们主要讨论函数输出方式。

print 函数语法

print(values,…,sep=’ ‘,end=’\n’,file=sys.stdout)

参数说明:

  • values:要输出的对象,可以是数字,字符串,列表等;省略号表示一次可以输出多个对象,中间用 , 隔开。
  • sep:分隔符。当输出两个或者两个以上的对象时,对象与对象之间默认使用空格’ ‘分隔开。
  • end:输出所有对象后,默认换行。\n代表换行。
  • file:设置输出设备,默认输出到显示器。
import sys

print(10, 'abc')
print(11, 'abc', sep=',')
print(12, 'abc', True, sep=',', end='!')
print(13, 'abc', sep=',', end='\n', file=sys.stdout)
print(14, 'abc', sep=',', file=sys.stderr)

输出结果:

image-20240904164152507

格式化输出

print 函数中,我们有多种方式进行格式化输出:

  • 占位符方式
  • format 方式
  • f-string 方式
占位符方式

使用占位符(%)格式化输出

#语法格式:
'%[-][+][0][m][.n] 格式化字符' % 输出对象
  • -:可选参数,指定左对齐
  • +:可选参数,指定右对齐
  • :可选参数,表示右对齐,用 填充空白处(一般和 m 参数一起使用)
  • m:可选参数,指定占用宽度
  • n:可选参数,指定小数点后保留位数
  • 格式化字符:必须参数。

格式化字符:

通配符 说明 代码 结果
%s 输出一个字符串,字符串采用 str() 的显示 msg=’Hello,world’
print(‘%s’ % msg)
Hello,world
%c 输出一个单一的字符 print(‘%c’ % 90) Z
bin 二进制整数 print(bin(50)) 0b110010
%hd%d%ld 以十进制、有符号的形式输出 shortintlong 类型的整数 print(‘%d’ % 50) 50
%f%lf%F 以十进制的形式输出 floatdouble 类型的浮点数 i= 2.6714563467
print(‘%f’ % i)
2.67146

格式化字符串有很多中通配符,这里就罗列了常见的一些情况,有兴趣的童鞋可以下来自行搜索。

data = 555
print('%-d'%data) #左对齐

#输出:
555

data = 555
print('%5d'%data) #占用宽度为5

#输出:
  555 #左边两个空位

data = 555
print('%05d'%data) #占用宽度为5,用0填充空位

#输出:
00555

data = 555.222222
print('%.2f'%data) #保留两位小数

#输出:
555.22
format 格式化

可以调用方法 format 并使用花括号作为占位符,从而得到格式化字符串。

img

最简单的方法就是使用内置函数 format 得到格式化字符串,它与字符串的方法 format 是等价的。

  1. format 中的内容和花括号的出现顺序一一对应

    name = '关为'
    gender = '男'
    age = 19
    print('我是{},性别{},今年{}岁'.format(name, gender, age))
  2. 花括号中填入数字指定 format 中的参数(数字从0开始)

    name = '关为'
    gender = '男'
    age = 19
    print('我是{1},性别{0},今年{2}岁'.format(age, name, gender))

    注意:这里的数字和 format 中的变量的顺序对应,

  3. 通过关键字指定

    name = '关为'
    gender = '男'
    age = 19
    print('我是{name},性别{gender},今年{age}岁'.format(name=name, gender=gender, age=age))
f-string 方式

f-stringpython3.6 之后版本添加的,称之为字面量格式化字符串,是新的格式化字符串的语法。

f-string 格式化字符串以 f 开头,后面跟着字符串,字符串中的表达式用大括号 {} 包起来,它会将变量或表达式计算后的值替换进去,实例如下:

name = '关为'
gender = '男'
age = 19
print(f'我是{name},性别{gender},今年{age}岁')

输入操作

Python 使用 input 输入变量,input 输入的变量为字符串形式,可以通过其他方式转换为整型或其他类型。

单行输入已知个数的字符串

# 分别输入两次(以回车为一次输入结束)
name1 = input()
name2 = input('请输入姓名:')
print(f'第一个学生叫:{name1},第二个学生叫:{name2}')

# 单行读入含有一个空格的字符串,并按照空格分隔开,存进name1,name2中
name1, name2 = input('请输入姓名:').split()
print(f'第一个学生叫:{name1},第二个学生叫:{name2}')

# 单行读入含有一个逗号的字符串,并按照逗号分隔开,存进name1,name2中
name1, name2 = input('请输入姓名:').split(',')
print(f'第一个学生叫:{name1},第二个学生叫:{name2}')

注意:如果控制台不能输入中文,是 Pycharm2024 版本问题,可以在其他地方输入后复制过来,或者更新版本。

单行输入已知个数的数字

# 单行读入单个整数b
b = int(input())

# 单行读入单个浮点数b 
b = float(input())

# 单行读入用空格隔开的两个整数a,b 
a, b = map(int, input().split())    

单行输入不定个数的数字

# 单行读入不定个整数(整数之间用空格分隔),从0开始存入列表a中,回车代表结束
a = list(map(int,input().split()))

流程控制

流程控制是计算机运算领域的用语,意指在程序运行时,个别的指令(或是陈述、子程序)运行或求值的顺序。不论是在声明式编程语言或是函数编程语言中,都有类似的概念。

在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能。

简单理解:流程控制就是来控制我们的代码按照什么结构顺序来执行。

流程控制主要有三种结构,分别是顺序结构、分支结构和循环结构,这三种结构代表三种代码执行的顺序。

image-20240907194132943

顺序结构

顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。

分支结构

在所有编程语言中与我们平时写的很多程序中,我们几乎都要运用到判断语句,通过判断语句来帮助我们写的这个程序判断是否达到某个代码块运行的条件。因此我们想实现判断条件是否符合某个代码块运行的条件,那么我们就需要运用到判断语句。

Python 中,判断语句有 ifif…elseif…elif…else。关键词有 orand

分支结构包括:

  • 单层分支结构:根据一个条件决定是否执行某个代码块。
  • 双层分支结构:根据一个条件决定执行两个代码块中的一个。
  • 多层分支结构:根据多个条件选择执行不同的代码块。
  • 条件表达式:简洁的条件操作方式。
  • 组合条件:使用逻辑运算符组合多个条件。
  • match 语句:Python 3.10 及以上版本的模式匹配。

单层分支结构

单分支结构仅在条件为真时执行特定的代码块,否则不执行任何操作。

语法
if 条件:
  操作
案例
from random import random

num = int(random() * 100 + 1)
if num % 2 == 0:
    print(num, 'is even')

这段代码的意思是:当 num 的值是偶数时,输出内容。

练习
  1. 用户输入一个数,判断其是否是偶数。如果是,则输出 YES
  2. 用户输入一个数,判断其是否是 5 的倍数而不是 7 的倍数。如果是,则输出 YES
  3. 用户输入一个数,系统生成一个数,判断这个数是否猜中。
注意
  • 单分支结构适用于当条件不满足时无需执行其他操作的情况。
  • 如果条件永远为假,代码块将永远不会执行。
  • if 中的操作不能和 if 并列,即需要空格缩进。

双层分支结构

双分支结构在条件为真时执行一个代码块,在条件为假时执行另一个代码块。

语法
if 条件:
    操作1
else:
    操作2
案例
num = int(input("Enter a number: "))
if num % 2 == 0:
    print(num, 'is an even number.')
else:
    print(num, 'is an odd number.')

这段代码的意思是:当 num 的值是偶数是输出 if 中的操作;否则输出 else 中的操作。

练习
  1. 用户输入一个数,判断其是否是同时被 3 和 5 整除。如果是,则输出 YES,否则输出 NO

  2. 用户输入一个四位数,判断其是否是对称数。如果是,则输出 YES,否则输出 NO。例如:4224就是对称数。

  3. 用户输入一个用 24 小时制表示的时间,把它转换为用 12 小时制表示的时间并输出。如:输入1807(18点07分),则输出6:7 PM

  4. 用户输入一个三位数,判断这个数是否时水仙花数。(水仙花数是指一个 3 位数,它的每个位上的数字的 3 次幂之和等于它本身(例如:1^3 + 5^3+ 3^3 = 153))

注意
  • else 部分是可选的,但如果存在,则 if 条件为假时会执行 else 部分的代码。

多层分支结构

多分支结构使用 ifelifelse,可以处理多个条件。

语法
if 条件1:
  操作1
elif 条件2:
  操作2
....
else:
  操作n
案例
score = int(input("Enter a score: "))
if score == 100:
    print('成绩是:', score, '很完美!')
elif score >= 85:
    print('成绩是:', score, '很优秀!')
elif score >= 70:
    print('成绩是:', score, '很不错!')
elif score >= 60:
    print('成绩是:', score, '及格了!')
else:
    print('成绩是:', score, '有点差!')

根据 score 选择执行其中一条操作。

练习
  1. 随机产生一个天气的气温,给出用户合理的穿衣提醒。

  2. 用户输入三个整数,根据对三个数的比较关系显示如下信息:

    • 如果三个数都不相等则显示 0 ;
    • 如果三个数中有两个数相等则显示 1 ;
    • 如果三个数都相等,则显示 2 。
  3. 练习3:编写程序,对不同车速进行判断,给出警告或者奖励:

    • 车速大于 100 并小于 120,提示车辆超速;
    • 车速大于 120,给出警告;
    • 车速大于 80 且小于 100,给予奖励。
注意
  • elifelse if 的缩写,可以有多个 elif 分支。
  • else 部分是可选的,如果没有匹配的条件且没有 else,则不执行任何操作。

嵌套分支

嵌套分支结构在一个分支结构内部包含另一个分支结构,用于处理更加复杂的条件判断。

temperature = int(input("请输入当前温度: "))
humidity = int(input("请输入当前湿度: "))

if temperature > 30:
 if humidity > 70:
     print("天气闷热,请注意防暑降温!")
 else:
     print("天气炎热,请保持通风!")
else:
 if humidity > 70:
     print("天气潮湿,请注意防潮!")
 else:
     print("天气舒适,享受美好的一天!")

输出结果:

根据温度和湿度的组合,输出不同的建议:

  • 高温高湿:“天气闷热,请注意防暑降温!”
  • 高温低湿:“天气炎热,请保持通风!”
  • 低温高湿:“天气潮湿,请注意防潮!”
  • 低温低湿:“天气舒适,享受美好的一天!”

注意事项:

  • 嵌套过深的分支结构会使代码变得复杂难读,建议保持层次清晰。
  • 尽量避免嵌套层次过深,可以考虑重构代码或使用其他控制结构。

条件表达式

条件表达式,也称为三元运算符,提供了一种简洁的条件判断方式,非常适合在一行代码中进行简单的条件判断。

age = int(input("请输入你的年龄: "))
status = "成年" if age >= 18 else "未成年"
print(f"你是{status}。")

输出结果:

  • 如果年龄 ≥ 18:”你是成年。”
  • 如果年龄 < 18:"你是未成年。"

注意事项:

  • 使用条件表达式时,确保代码简洁清晰。
  • 适合用在简单的条件判断和赋值场景。

组合条件

组合条件使用逻辑运算符(andornot)来检查多个条件。

age = int(input("请输入你的年龄: "))
has_ticket = input("是否持有票证?(yes/no) ").lower() == "yes"

if age >= 18 and has_ticket:
    print("欢迎进入剧场!")
else:
    print("抱歉,你不能进入剧场。")

输出结果:

  • 如果年龄 ≥18 且有票:“欢迎进入剧场!”
  • 否则:“抱歉,你不能进入剧场。”

注意事项:

  • 使用 and 时,所有条件都必须为真。
  • 使用 or 时,只要一个条件为真即可。

match 语句

Python 3.10 引入了 match 语句,为条件判断提供了模式匹配的功能。match 语句类似于其他语言中的 switch 语句,但功能更为强大和灵活。

语法
match value:
    case pattern1:
        # 执行代码块1
    case pattern2:
        # 执行代码块2
    case _:
        # 默认代码块
案例
num = int(input("Enter a number: "))
match num:
    case 1:
        print(num, "is a A")
    case 2:
        print(num, "is a B")
    case 3 | 4:
        print(num, "is a C or D")
    case _:
        print(num, "is not an A or B or C or D")

根据用户的输入的 num 来决定进入到那个 case 块中。

注意
  • match 语句在 Python 3.10 及以上版本中可用。
  • 尤其注意段落缩进,matchcase 和操作之间的缩进。
  • 可以使用 | 来进行或者操作。
  • 在使用时,确保所有可能的输入都被覆盖到,尤其是要有一个默认的处理分支。
  • _ 是通配符,表示一定会匹配成功,必须在最后一个 case 块中。
  • 还有其他更多的写法,会在以后章节介绍。

循环结构

循环结构是指在满足一定条件时重复执行某段代码的结构。这种结构使得程序能够高效地处理重复性的任务。Python 提供了两种基本的循环结构:while 循环和 for 循环。

循环的要素

每个循环结构通常包含以下几个基本要素:

  • 初始条件:确定循环开始前的一些初始设置。
  • 循环条件:决定循环是否继续进行的条件表达式。
  • 循环体:循环中需要重复执行的代码块。
  • 更新条件:用于修改循环条件,使得循环可以终止。

while 循环

while 循环是 Python 中的一种基本循环结构,适用于在条件为真时重复执行某段代码。

语法
while 条件:
    # 循环体
    # 更新条件
案例
num = 1
sum = 0
while num < 101:
    sum = sum + num
    num = num + 1
print('1-100之和是:', sum)

计算 1-100 之和。

练习
  1. 通过 while 循环计算 1-100 之间的偶数和。
  2. 用户输入一个三位数,判断这个数是否是对称数。
  3. 用户输入一个数,逆序输出。
注意
  • 确保循环条件最终能够变为假,否则会造成无限循环。
  • 更新条件的位置和内容要慎重,避免跳过或遗漏。

for 循环

for 循环是 Python 中另一个常用的循环结构,通常用于遍历序列(如列表、字符串、元组等)。

语法
for 变量 in 序列:
    # 循环体
案例
for i in ['西安', '宝鸡', '渭南']:
    print(i)

循环输出的三个城市,每次循环时,将列表中的一个城市依次赋予变量 i

整合 range

range 函数在 Python 中非常常用,尤其是在 for 循环中。range 函数生成一个整数序列,通常用于控制循环的次数。

range 主要有三种使用情况,分别是:

  1. range(stop)

    这种形式生成从 0 到 stop - 1 的整数序列,适用于循环次数已知的情况。

    sum = 0
    for i in range(101):
        sum += i
    print(sum)

    计算 1-100 之和。

  2. range(start,stop)

    这种形式生成从 startstop - 1 的整数序列。

    sum = 0
    for i in range(1, 101):
        sum += i
    print(sum)
  3. range(start,stop,step)

    这种形式生成从 startstop - 1 的整数序列,step 表示步长,可以是正数或负数。

    sum = 0
    for i in range(1, 101, 2):
        sum += i
    print(sum)

    计算 1-100 之间的奇数和。

练习
  1. 求出1/1+1/2+1/3+1/4+…+1/10之和。
  2. 求出100 – 1000之内的水仙花数。
  3. 用户输入一个数,求出这个数的阶乘。例如:5,就是求出 1*2*3*4*5
  4. 现有 50 瓶可乐,3 个可乐瓶盖可以换一瓶可乐,那么一个人能喝多少瓶可乐。
注意
  • for 循环中的序列可以是列表、元组、字符串或其他可迭代对象。
  • for 循环中的序列迭代需要使用到 range 函数。

两个关键字

在循环中,breakcontinue 语句用于控制循环的执行流程。

break 关键字

break 语句用于立即终止循环,不再执行循环体中的剩余代码或后续的迭代。

for i in range(1, 11):
    print(i)
    if i == 6:
        break
print('我是循环之外的内容')

输出结果:

image-20240910103444738

在这个例子中,当 i等于 6 时,break 语句会立即终止循环,所以 6 后续的数字不会被打印。

continue 关键字

continue 语句用于跳过当前循环体中的剩余代码,立即进入下一次迭代。

sum = 0
for i in range(1, 101):
    if i % 2 == 0:
        continue
    sum += i
print('我是循环之外的内容,输出1-100之间的奇数和:', sum)
image-20240910104506007

在这个例子中,我们统计了 1-100 之间的奇数和,统计方式为,当 i 为偶数时,通过 continue 跳出当次循环,不会执行求和代码。

在本节中,我们详细介绍了 Python 中的 while 循环和 for 循环,以及如何使用 breakcontinue 语句控制循环的执行。我们还讨论了如何使用 range 函数生成数字序列,并结合 for 循环执行重复性任务。循环结构是编写高效和动态程序的关键,可以大大简化需要重复执行的任务。

Python 中的函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

函数能提高应用的模块性,和代码的重复利用率。你已经知道 Python 提供了许多内建函数,比如 print()。但你也可以自己创建函数,这被叫做用户自定义函数

自定义函数

image-20241020170337419

函数的定义

使用关键字 def,确定函数名称、参数名称、参数个数、编写函数体(用于实现函数功能的代码)。

def 函数名(参数):
  函数主体
  [return 返回值]
  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数如果没有内容,可以书写 pass 占位。
  • return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None
def fun(a,b):
  """
  函数说明:执行特定操作

  参数:
    a (int): 第一个参数
    b (int): 第二个参数

  返回:
    bool: 操作结果
  """
  return a > b

函数的调用

通过函数名称进行调用函数,定义好函数之后,只表示这个函数封装了一段代码而已,如果不主动调用函数,函数是不会主动执行的。

def method_a():
  print('我是函数a')
# 函数调用
method_a()

函数的参数

函数中的参数分为:形式参数和实际参数。

  • 形参:是函数定义时小括号里的参数,是用来接收参数的,在函数内部作为变量使用。

  • 实参:是函数调用时小括号里的参数,是用来把数据传递到函数内部的。

def method_b(a,b):
  print(f'接收的参数a:{a},b:{b}')

method_b(3,7)
参数的默认值

定义函数时,可以给某个参数指定一个默认值,具有默认值的参数就叫做缺省参数。

def method_c(a, b=2):
    print(f'接收的参数a:{a},b:{b}')

method_c(3) # 接收的参数a:3,b:2
method_c(3,5) # 接收的参数a:3,b:5

注意:可选参数要定义在非可选参数的后面。

可变参数

传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。

def method_d(*args):
    print(f'接收的参数:{args}')

method_d(3)  # 接收的参数:(3, 5)
method_d(3, 5)  # 接收的参数:(3, 5)
method_d(3, 5, 'abc')  # 接收的参数:(3, 5, 'abc')
字典形式

传入的参数个数是可变的,但是它的数据类型是字典形式。

def method_e(**num):
    print(f'接收到的参数是:{num}')
method_e(a=2, b=3)  # 接收到的参数是:{'a': 2, 'b': 3}

注意:这里的 ab 名称没有特别要求,只是字典中的 key 而已。

函数的返回值

return [表达式]语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的 return 语句返回 None

from random import random

def method_a():
    num = int(random() * 100 + 1)
    return num

num = method_a()
print(f'返回结果是:{num}') # 返回结果是:17

Pass 语句

Pythonpass 是空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句。

Python 语言 pass 语句语法格式如下:

def 函数名():
  pass

该处的 pass 便是占据一个位置,因为如果定义一个空函数程序会报错,当你没有想好函数的内容是可以用 pass 填充,使程序可以正常运行。

注意

对于空函数而言,Python2 是必填项,必须书写 pass 关键字。但是到了 Python3 中,pass 关键字可以被省略,但是并不推荐大家这样去做。

Python 中的主函数

Python 中,主函数是程序的入口点,通常命名为 main()。它是程序执行的起点,用于执行主要逻辑。

主函数可以通过 if __name__ == '__main__': 判断直接运行或导入。主函数可以组织代码、调用其他函数、处理用户输入等,并且可以接受参数,提高代码的灵活性和可维护性。

Python 中,主函数的定义通常放在脚本的最后部分,这样可以先定义其他辅助函数和全局变量,然后在主函数中调用这些函数和变量。主函数可以包含任意的代码,用来实现具体功能,如读取文件、处理数据、调用其他函数、输出结果等。

if __name__ == '__main__':
        # 这里就是主函数要执行的代码

变量作用域

全局变量

全局变量是在函数外部定义的变量,所有函数内部都可以使用这个变量。

age = 18
name = '张三'

def method_a():
    print(f'姓名是:{name},年龄{age}岁')

method_a()

其他模块也可以使用这个变量,当然需要通过 import 导入这个模块后在通过模块名.变量方式使用。

局部变量

局部变量是在函数内部定义的变量,只能在函数内部使用。

def method_b():
    name = '李四'
    age = 17
    print(f'姓名是:{name},年龄{age}岁')

method_b()

如果全局变量和局部变量重名了:

age = 18
name = '张三'

def method_a():
    print(f'姓名是:{name},年龄{age}岁')

def method_b():
    name = '李四'
    age = 17
    print(f'姓名是:{name},年龄{age}岁')

method_a() # 姓名是:张三,年龄18岁
method_b() # 姓名是:李四,年龄17岁

当局部变量与全局变量同名时,局部变量会覆盖全局变量,导致无法直接访问全局变量。也就是说,只能使用局部变量。

匿名函数

Python 使用 lambda 来创建匿名函数。

所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

  • lambda 只是一个表达式,函数体比 def 简单很多。
  • lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然 lambda 函数看起来只能写一行,却不等同于 CC++ 的内联函数,内联函数的目的是调用小函数时不占用栈内存从而减少函数调用的开销,提高代码的执行速度。

语法格式:

lambda [arg1 [,arg2,.....argn]]:expression

例如:传递两个参数,返回他们的和。

result = lambda a, b: a + b

num = result(4, 6)
print(f'计算后的结果是:{num}')  # 计算后的结果是:10

递归函数

一个函数调用了自身,就被称之为递归函数。

def method_a(i, sum=0):
    sum += i
    i = i + 1
    if i < 101:
        method_a(i, sum)
    else:
        print(f'1-100之和是:{sum}')

method_a(1)

上述代码计算了1-100之和。

Python 中的列表

Python 编程中,列表是最常用的数据结构之一。它不仅可以存储多种类型的元素,还提供了丰富的操作方法,列表是可变的,这意味着列表中的元素可以在创建后被修改。列表的灵活性和易用性使得它成为处理数据的首选结构之一。本章将详细介绍列表的定义、基础操作、进阶操作以及实际应用场景。

列表的介绍

列表是 Python 中的一种数据结构,用于存储有序的元素集合。列表使用方括号([])表示,元素之间用逗号分隔。列表中的元素可以是任意类型,包括其他列表。

列表名 = [列表内容]

例如:

list1 = [2, 6.5, True, 'Hello']
print(list1)

列表的长度可以动态变化,可以随时添加或删除元素。列表中的元素可以通过索引访问,索引从 开始。

列表的特点

  • 有序性:列表中的元素是有序排列的,每个元素都有一个唯一的索引。
  • 可变性:列表是可变的,可以随时修改其内容。
  • 混合数据类型:列表可以包含不同类型的元素,例如整数、字符串、甚至其他列表。
  • 动态调整大小:列表的大小可以动态变化,添加和删除元素非常方便。

列表的操作

你可以通过索引访问列表中的元素,索引从 开始。负数索引表示从列表末尾开始的元素。列表是可变的容器,可以修改其中的元素。可以向列表中添加或删除元素。

元素的访问

可以通过索引下标访问列表中的元素。

list1 = ['西安', '南京', '上海', '杭州', '北京', '兰州', '榆林']
# 获取列表中的元素
# 将列表中的第四个元素赋予n1
n1 = list1[3]
# 将列表中的倒数第二个元素赋予n2
n2 = list1[-2]
n3 = list1[9]  # ❌ 索引号越界了
print(n1, n2)

需要注意的是:

  • 列表的索引从 0 开始,最后一个元素的索引是 -1。
  • 尝试访问不存在的索引会引发 IndexError

遍历列表

遍历列表是处理列表元素的常见操作。你可以使用 for 循环来遍历列表中的每个元素。

list1 = ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']
for e in list1:
    print(e, end=',')
print('\n循环之外的内容')

元素的修改

也是可以通过元素下标修改列表中的元素。

list1 = ['西安', '南京', '上海', '杭州', '北京', '兰州', '榆林']
# 修改列表中的第三个元素为‘苏州’
list1[2] = '苏州'
print(list1)

元素的添加

因为 Python 中的列表是可变容器,可以动态向列表中添加元素。常用的方法是:

  • append(x) :在列表末尾添加元素 x
  • extend(iterable) :扩展列表,添加多个元素。
  • insert(index,x) :在指定位置 index 插入元素 x
list1 = ['西安', '南京', '上海', '杭州', '北京', '兰州', '榆林']
list1.append('汉中')
list1.extend(['武汉', '太原', '天津'])
list1.insert(3, '成都')
print(list1)  # ['西安', '南京', '上海', '成都', '杭州', '北京', '兰州', '榆林', '汉中', '武汉', '太原', '天津']

元素的删除

对于删除操作,可以使用 remove() 删除指定元素,pop() 删除并返回指定位置的元素。clear() 移除列表中的所有元素。

list1 = ['西安', '南京', '上海', '杭州', '北京', '兰州', '榆林']
list1.remove('上海')
list1.remove('沈阳') # ❌ 如果不存在沈阳 会报错
city1 = list1.pop() # 不指定位置 默认删除并得到最后一位
city2 = list1.pop(2) # 指定删除并得到第三位元素
print(list1)  # ['西安', '南京', '北京', '兰州']
print(city1) # 榆林
print(city2) # 榆林
list1.clear()
print(list1)  # []

元素的查找

要查找元素在列表中的位置或统计其出现次数,可以使用 index()count() 方法。

list1 = ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']
# 统计元素出现的位置
index1 = list1.index('西安')  # 返回第一次出现的位置
index2 = list1.index('西安', 2)  # 从第三个元素开始查找 返回第一次出现的位置
index3 = list1.index('杭州')
# index4 = list1.index('桂林') # ❌ 不存在会报错
print(index1, index2, index3, sep=',')  # 0,4,3
# 统计元素出现的次数
size1 = list1.count('西安')
size2 = list1.count('福州')
print(size1, size2, sep=',')  # 2,0

列表类型内建函数

Python 提供了一些内建函数,用于操作和处理列表。这些函数包括:

  • len():返回列表的长度。
  • max():返回列表中的最大值。
  • min():返回列表中的最小值。
  • sum():返回列表中所有元素的和(适用于数字列表)。
  • sorted():返回列表的排序副本。
  • reversed():返回列表的反转迭代器。
  • enumerated():返回列表中的元素和索引。
list1 = ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']
list2 = [46, 73, 24, 66, 91, 28]
len1 = len(list1)
print(len1)  # 计算元素个数
max1 = max(list1)
print(max1)  # 计算列表中的最大值
min1 = min(list1)
print(min1)  # 计算列表中的最小值
sum1 = sum(list2)
print(sum1)  # 统计和 只能是数字列表
sorted(list1)  # 排序 也可以使用list1.sort()
print(list1)
reversed(list1)  # 反转 也可以使用list1.reverse()
print(list1)
en1 = enumerate(list1)
for i, e in en1:
    print(f'索引号:{i},值是{e}')

列表的切片

使用切片操作符访问列表元素,切片操作符([:])允许从列表中提取子列表。切片操作返回一个新的列表,不修改原列表。

切片操作的基本语法是:

列表[开始:结束:步长]

其中开始结束是索引,步长表示元素间的间隔。

基本切片

最简单的切片操作只包含开始和结束索引。

list1 = ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']
list2 = list1[1:3]
list3 = list1[2:]
list4 = list1[-4:]
list5 = list1[:5]
print(list2)  # ['南京', '上海']
print(list3)  # ['上海', '杭州', '西安', '北京', '兰州', '榆林']
print(list4)  # ['西安', '北京', '兰州', '榆林']
print(list5)  # ['西安', '南京', '上海', '杭州', '西安']

步长切片

步长用于指定切片时的间隔。默认步长为1,表示连续提取元素。当步长为负数时,可以实现反向切片。

list1 = ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']
list2 = list1[::2]
list3 = list1[1::2]
list4 = list1[::-1]
list5 = list1[::-2]
print(list2)  # ['西安', '上海', '西安', '兰州']
print(list3)  # ['南京', '杭州', '北京', '榆林']
print(list4)  # ['榆林', '兰州', '北京', '西安', '杭州', '上海', '南京', '西安']
print(list5)  # ['榆林', '北京', '杭州', '南京']

省略切片

当省略开始或结束索引时,Python 会使用默认值。省略开始索引表示从列表的起始位置开始,省略结束索引表示到列表的末尾。

list1 = ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']
list2 = list1[:5]  # 省略了开始和步长
list3 = list1[2:]  # 省略了结束和步长
list4 = list1[:]  # 整个列表
print(list2)  # ['西安', '南京', '上海', '杭州', '西安']
print(list3)  # ['上海', '杭州', '西安', '北京', '兰州', '榆林']
print(list4)  # ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']

切片对象

切片对象是通过 slice(begin,end,step) 函数创建的,用于表示切片操作。切片对象可以用于在任何支持切片的对象中应用相同的切片。

这个内容我们目前练习下即可,更为详细的内容等到面向对象之后学习。

list1 = ['西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林']
slice_obj = slice(2, 6)
print(list1[slice_obj])  # ['上海', '杭州', '西安', '北京']

列表生成式

列表生成式是一种简洁的创建列表的方法,通常用于生成符合某种模式的列表。它的语法结构如下:

[expression for item in iterable if condition]
  • expression 是对每个元素的操作,可以是元素本身或对元素的处理结果。
  • item 是从迭代对象(iterable)中取出的每个元素。
  • iterable 是可以迭代的对象,例如列表或范围。
  • condition 是一个可选的条件,用于过滤元素。

生成数值列表

假设你想生成一个包含 1 到 10 的平方的列表,可以使用列表生成式:

list1 = [e ** 2 for e in range(1, 11)]
print(list1)

这段代码等同于:

list1 = []
for e in range(1, 11):
    list1.append(e ** 2)
print(list1)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

列表生成式的优势在于它更简洁明了,并且通常执行速度更快。它不仅减少了代码行数,还能提高代码的可读性,特别是在生成复杂的列表时。

过滤条件

你还可以在列表生成式中加入条件语句。例如,你可以在刚才的基础上引入筛选条件:

list1 = [e ** 2 for e in range(1, 11) if e > 5]
print(list1)  # [36, 49, 64, 81]

通过添加条件,你可以轻松地筛选出符合特定要求的元素,这对于处理和过滤数据非常有用。

字符串操作

列表生成式也可以用于处理字符串。假设你有一个包含多个单词的列表,想把每个单词转换成大写,可以这样做:

list1 = ['zhangsan', 'lisi', 'wangwu', 'maliu']
list2 = [e.upper() for e in list1]
print(list1)  # ['zhangsan', 'lisi', 'wangwu', 'maliu']
print(list2)  # ['ZHANGSAN', 'LISI', 'WANGWU', 'MALIU']

这种方法不仅简化了代码,还让转换逻辑更加直观和清晰。

总结

列表生成式让我们能够在一行代码中完成列表的创建和处理任务,这种写法既简洁又高效。但在使用时要注意保持代码的可读性,尤其是在生成式比较复杂的情况下。

嵌套列表

嵌套列表是指列表的元素本身也是列表。这种结构可以用于表示复杂的数据,如矩阵或表格。

比如说,我们可以使用嵌套列表描述一个班级学生信息:

classroom = []
title = ['编号', '姓名', '性别', '年龄']
stu1 = [101, '张三', '男', 27]
stu2 = [102, '李四', '女', 21]
stu3 = [103, '王五', '男', 23]
classroom.append(title)
classroom.append(stu1)
classroom.append(stu2)
classroom.append(stu3)
# [['编号', '姓名', '性别', '年龄'], [101, '张三', '男', 27], [102, '李四', '女', 21], [103, '王五', '男', 23]]
print(classroom)  

如果使用循环输出

classroom = []
title = ['编号', '姓名', '性别', '年龄']
stu1 = [101, '张三', '男', 27]
stu2 = [102, '李四', '女', 21]
stu3 = [103, '王五', '男', 23]
classroom.append(title)
classroom.append(stu1)
classroom.append(stu2)
classroom.append(stu3)
for i in range(0, len(classroom)):
    stu = classroom[i]
    for j in range(0, len(stu)):
        print(stu[j], end='\t')
    print()
print('我是循环之外的代码')

效果如下:

image-20240910160433955

本节课涵盖了 Python 列表的基础和进阶操作,包括创建列表、访问和修改元素、列表类型的内建函数、列表的切片、列表生成式和嵌套列表。通过这些内容,你可以更高效地处理数据,编写更加灵活和强大的 Python 程序。

Python 中的元组

Python 编程中,元组( tuple )是一种常用的数据结构,与列表类似,也是由一系列按特定顺序排序的元素组成,但不同的是,元组是不可变的。这种特性使得元组在某些需要确保数据不可变的场景下,比列表更适合使用。本章将详细介绍元组的定义、操作,以及元组在实际应用中的优势和场景。

定义与创建

元组是一种有序的数据结构,可以存储多个元素。这些元素可以是不同类型的,类似于列表。元组使用圆括号 () 定义,元素之间用逗号 , 分隔。

list1 = ('西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林')
print(list1)

元组可以包含任意数量的元素,这些元素可以是任何数据类型。元组的最大特点是它的不可变性,这意味着一旦创建,元组的内容就不能更改或删除。

元组的操作

你可以通过索引访问元组中的元素,索引从 0 开始。负数索引表示从元组末尾开始的元素。由于元组是不可变的,因此不能修改其中的元素。

list1 = ('西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林')
print(list1)
a1 = list1[3]
a2 = list1[-2]
print(a1)  # 杭州
print(a2)  # 兰州
list1[1] = '南昌'  # ❌

注意:

  • 元组的索引从 0 开始,最后一个元素的索引是 -1
  • 尝试修改元组中的元素会引发 TypeError,因为元组是不可变的。

遍历元组

遍历元组中的元素可以使用 for 循环,类似于列表的遍历。这种遍历方式在处理元组中的数据时非常方便,特别是在需要逐一处理每个元素的情况下。

list1 = ('西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林')
for e in list1:
    print(e)

元组的切片

切片允许你获取元组的一个子集。使用切片时,可以指定起始、结束和步长。切片操作非常灵活,可以从元组中提取出你需要的部分。

元组对于切片的操作基本上和列表一致。

list1 = ('西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林')
list2 = list1[:]  # ('西安', '南京', '上海', '杭州', '西安', '北京', '兰州', '榆林')
list3 = list1[1:6]  # ('南京', '上海', '杭州', '西安', '北京')
list4 = list1[1:7:2]  # ('南京', '杭州', '北京')
list5 = list1[-5:] # ('杭州', '西安', '北京', '兰州', '榆林')
print(list2)
print(list3)
print(list4)
print(list5)

注意:

  • 切片操作的结束下标从 1 开始计算。
  • 步长为负时,元组会从右向左截取。

元组的高级操作

打包和解包

元组的打包是指将多个元素组合成一个元组,而解包是将一个元组拆分成多个变量。打包和解包操作使得元组在函数返回值、数据交换等场景中非常有用。例如,你可以使用元组返回多个值,或者将元组解包到多个变量中。

list1 = '西安', '南京', '合肥'
print(list1)  # ('西安', '南京', '合肥')
# 注意:解包的时候数量要对应上
city1, city2, city3 = list1
print(city1, city2, city3)  # 西安 南京 合肥

这种打包和解包的特性使得元组在处理多个相关的数据时非常有用。特别是在返回多个值的函数中,元组可以让代码更加简洁和直观。

使用星号表达式进行解包

在解包时,如果元组中的元素个数多于变量个数,可以使用星号表达式 * 来捕获多余的元素。这种方式非常灵活,特别适合处理不定长度的元组。

list1 = '西安', '南京', '合肥', '深圳', '福州', '苏州'
firstCity, *middleCity, lastCity = list1
# 第一个城市:西安, 中间的城市:['南京', '合肥', '深圳', '福州'],最后的城市: 苏州
print(f'第一个城市:{firstCity}, 中间的城市:{middleCity},最后的城市: {lastCity}')  

需要注意的是:星号表达式捕获的部分总是一个列表,即使没有元素。

交换变量的值

元组的解包操作可以方便地交换两个变量的值,而无需借助中间变量。这在许多编程任务中非常有用,例如交换变量的值或旋转数据。

city1, city2 = '西安', '福州'
print(city1, city2)  # 西安 福州
city1, city2 = city2, city1
print(city1, city2)  # 福州 西安

这种交换操作不仅简洁,还避免了使用中间变量的复杂性和潜在的错误。

元组和列表的区别

元组和列表在 Python 中都是用于存储一系列数据的容器类型,但它们有一些关键的不同点,这使得它们适用于不同的场景。

  1. 可变性

    最大的区别在于可变性

    • 列表是可变的,这意味着一旦创建,我们可以随时添加、删除或修改其中的元素。
    • 元组则是不可变的,一旦定义,其内容就不能改变。

    这一特性使得元组在需要保护数据不变的场景下特别有用,例如传递配置参数或作为函数的返回值来确保数据的完整性。

  2. 使用场景

    • 元组由于其不可变特性,它们通常用于:

      • 存储不希望被改变的数据,如地理坐标(纬度、经度)、RGB 颜色值等。

      • 作为函数的返回值,提供多种不同类型的数据。

      • 作为字典的键(因为元组是可哈希的,而列表不是)。

    • 列表的可变性使它们更适合用于需要频繁修改的数据集,如用户输入、数据分析等。

  3. 性能

    在一些场景下,元组的性能比列表更好。由于元组是不可变的,Python 可以更优化地处理它们。比如,元组的内存使用通常比相同内容的列表少,而且在遍历和访问速度上,元组也可能略快于列表,特别是在大数据集的情况下。

    import timeit
    
    # 测试遍历列表和元组的时间
    print('列表遍历时间: %.3f 秒' % timeit.timeit('for x in [1, 2, 3, 4, 5, 6, 7, 8, 9]: pass', number=10000000))
    print('元组遍历时间: %.3f 秒' % timeit.timeit('for x in (1, 2, 3, 4, 5, 6, 7, 8, 9): pass', number=10000000))
  4. 数据安全与一致

    元组的不可变性提供了额外的安全性。这意味着一旦元组被创建,其内容就不会被无意修改。这在多线程环境中尤其有用,减少了数据竞争的风险。

    此外,不可变数据结构的使用可以确保数据的一致性,例如在配置文件中存储参数时使用元组。

  5. 数据结构的选择

    选择使用元组还是列表应根据具体的应用场景决定。

    • 如果数据集需要频繁修改或动态更新,列表是更好的选择;

    • 如果数据集需要固定不变,或者作为字典的键,元组则更为适合。

    理解这些区别可以帮助开发者做出更合理的选择,以优化代码性能和可维护性。

元组作为一种不可变的数据结构,在 Python 中提供了一种安全且高效的方式来存储和操作多个数据项。它们的不可变性确保了数据的安全性,在多线程环境中减少了数据竞争的风险。

此外,元组在性能上也具有优势,特别是在需要频繁读取数据而不修改的场景下。

元组和列表各有其适用的场景,理解它们之间的区别和使用场景,可以帮助我们在编程中做出更合理的选择。

Python 中的集合

集合(set)是一种独特的、无序的数据结构,在许多编程任务中发挥着重要作用。集合的特点是其元素的唯一性,这使得它非常适合用于数据去重、集合运算等场景。

在本篇文章中,我们将详细介绍 Python 中的集合,包括其定义、基本操作、集合运算、比较运算以及不可变集合 frozenset 的使用。

定义与创建

集合是无序且元素唯一集合体。我们可以使用大括号 {} 或内置函数 set() 来创建集合。在 Python 中,空的大括号 {} 通常表示一个空字典,因此要创建一个空集合,需要使用 set() 函数。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
list1 = ['西安', '上海', '深圳', '福州', '西安', '成都']
city2 = set(list1)
city3 = {'西安', 1, city1}  # ❌
# 输出内容乱序,每次都可能不一致
print(city1)  # {'上海', '福州', '西安', '深圳', '成都'}
print(city2)  # {'成都', '上海', '深圳', '西安', '福州'}
print(city3)

注意事项:

  • 集合中的元素是无序的,因此在不同运行时可能会以不同的顺序显示。
  • 集合中的元素都是唯一的,重复的数据不能录入。
  • 集合的元素必须是可哈希的,这意味着它们必须是不可变的数据类型。常见的可哈希数据类型包括整数、浮点数、字符串和元组。列表和集合因为是可变的,因此不能作为集合的元素。

集合的操作

添加元素

集合是可变的,可以使用 add() 方法添加新元素

city1 = {'西安', '福州'}
city2 = {}
city3 = set([])
city1.add('太原')
city2.add('太原')  # ❌ 'dict' object has no attribute 'add'
city3.add('太原')  # 空集合只能通过这种方式赋值
print(city1)
print(city2)
print(city3)

注意事项:

  • 直接使用 {} 产生的空集合不能 add() 赋值。
  • 可以使用 set([]) 方式定义空集合。

删除元素

集合中通过使用 remove()discard() 方法删除元素。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
city1.remove('上海')
city1.remove('宁波')  # ❌ 不存在会报错
city1.discard('深圳')
city1.discard('南京')  # 不存在不会报错
print(city1)
city1.clear() # 清空元素

注意事项:

  • remove() 方法在尝试删除不存在的元素时会引发 KeyError,而 discard() 方法不会引发错误。
  • clear() 清空集合,获取到的集合是 set()

遍历集合

集合是无序的,因此不能通过索引访问其元素。不过,我们可以使用for循环来遍历集合中的每个元素。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
for e in city1:
    print(e)
print('集合之外的内容')

集合的运算

交集运算

交集运算可以找到两个集合中的共同元素。可以使用 & 运算符或 intersection() 方法。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
city2 = {'福州', '南京', '深圳', '广州', '苏州'}
print(city1 & city2)  # {'深圳', '福州'}
print(city2.intersection(city1))  # {'深圳', '福州'}

并集运算

并集运算将两个集合中的所有元素合并,并去除重复的部分。可以使用 | 运算符或 union() 方法。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
city2 = {'福州', '南京', '深圳', '广州', '苏州'}
print(city1 | city2)  # {'成都', '南京', '西安', '深圳', '广州', '福州', '上海', '苏州'}
print(city2.union(city1))  # {'成都', '南京', '西安', '深圳', '广州', '福州', '上海', '苏州'}

差集运算

差集运算返回一个集合中的元素,这些元素在另一个集合中不存在。可以使用 - 运算符或 difference() 方法。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
city2 = {'福州', '南京', '深圳', '广州', '苏州'}
print(city1 - city2)  # {'成都', '西安', '上海'}
print(city2.difference(city1))  # {'南京', '广州', '苏州'}

对称差集运算

对称差集运算返回两个集合中不共有的元素。可以使用 ^ 运算符或 symmetric_difference() 方法。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
city2 = {'福州', '南京', '深圳', '广州', '苏州'}
print(city1 ^ city2)  # {'成都', '广州', '上海', '南京', '苏州', '西安'}
print(city2.symmetric_difference(city1))  # {'成都', '广州', '上海', '南京', '苏州', '西安'}

比较运算

集合之间可以进行比较运算,用于比较两个集合是否包含完全相同的元素(即元素值相同且数量相同)。

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
city2 = {'福州', '南京', '深圳', '广州', '苏州'}
# 这里可以使用关系运算符
print(city1 == city2)  # False

注意:比较运算符的结果是布尔值,用于表示集合之间的关系。

  • 去重特性:集合自动去重,因此重复元素(如 {'福州', '福州'} 实际为 {'福州'})。
  • ‌顺序无关性:集合不保证元素顺序,因此 {1, 2, 3} 等同于 {3, 2, 1}

不可变集合

Python 中的 frozenset 是一种不可变的集合类型。与 set 不同,frozenset 一旦创建,就不能再修改其内容。这对于需要不变的数据集合非常有用。

city1 = frozenset(['西安', '上海', '深圳', '福州', '西安', '成都'])
city2 = frozenset(['福州', '南京', '深圳', '广州', '苏州'])
city1.add('武汉')  # ❌ 只读集合
# 集合的其他函数不可变集合也都有
print(city1 & city2)
print(city1 | city2)
print(city1 - city2)
print(city1 ^ city2)
print(city1 >= city2)

列表和集合转换

在现实生活中,我们会大量的使用集合或者列表,有时就会涉及到它们之间的转换问题。

列表转集合

city1 = ['西安', '上海', '深圳', '福州', '西安', '成都']
city2 = set(city1)
print(city2, type(city2))

集合转列表

city1 = {'西安', '上海', '深圳', '福州', '西安', '成都'}
city2 = list(city1)
print(city2, type(city2))

应用场景

集合在实际编码中的应用广泛,特别是在处理需要数据去重、快速查找和过滤等任务时。下面,我们将举一些具体的例子,展示集合在这些场景中的使用。

去重操作

在许多情况下,我们需要从数据中去除重复的元素。集合的天然去重特性使它非常适合这个任务。

city1 = ['西安', '上海', '深圳', '福州', '西安', '成都']
city2 = set(city1)
city1 = list(city2)

其实就是上边的案例,我们将用户输入的列表转换为集合,自动去除了重复的元素。然后,我们将集合转换回列表,以保留列表的特性。

快速查找

集合的查找操作非常高效,时间复杂度为 O(1),这使得集合非常适合用于查找操作。

city1 = {'西安', '宝鸡', '商洛', '渭南', '咸阳', '榆林'}
city2 = set(input('请输入城市:').split(','))
print('存在的城市有:', city1 & city2)

在这个示例中,我们使用集合的交集操作来快速检查用户输入的城市中是否存在于我们的集合中。

集合的交集操作非常高效,特别适合这种场景。

数据过滤

集合还可以用于过滤数据。例如,我们可能希望从一组数据中移除一些特定的元素。

city1 = {'西安', '宝鸡', '商洛', '渭南', '咸阳', '榆林'}
city2 = set(input('请输入城市:').split(','))
print('不存在的城市有:', city2 - city1)

在这个例子中,我们通过集合的差集运算符 - 移除了 city1 集合中的特定项。差集运算符的使用使得代码简洁明了。

集合在 Python 编程中提供了一个强大的工具,用于处理数据去重、快速查找和数据过滤等任务。通过结合使用集合的各种运算,我们可以有效地解决许多常见的编程问题。集合的独特特性使它在处理无序数据和保证数据唯一性方面尤为出色。

Python 中的字典

很多时候,数据对应的元素之间的顺序是无关紧要的,因为各元素都具有特别的意义,例如存储一些朋友的手机号码,此时用序列来存储数据并不是一个好的选择,Python 提供了一个很好的解决方案——使用字典数据类型。

Python 中,字典是属于映射类型的数据结构。字典包含以任意类型的数据结构作为元素的集合,同时各元素都具有与之对应且唯一的键,字典主要通过键来访问对应的元素。

字典与列表、元组有所不同,后两者使用索引来对应元素,而字典的元素都拥有各自的键,每个键值对都可以看成是一个映射对应关系。

此外,元素在字典中没有严格的顺序关系。由于字典是可变的,所以可以对字典对象进行元素的增删改查等基本操作。

定义与创建

字典的创建有两种方式,{} 方式和 dict 函数方式。

花括号方式

只要将字典中的一系列键和值按照键值对的格式(key:value,即键:值)传入花括号 { } 中,并以逗号将各键值对隔开,即可实现创建字典,具体创建格式如下。

dict={key_1:value_1, key_2:value_2, … , key_n:value_n}

若在花括号中不传入任何键值对,则会创建一个空字典。如果创建字典时重复传入相同的键,因为键在字典中不允许重复,所以字典最终会采用最后出现的重复键的键值对。

注意:dict 作为 Python 的关键字和内置函数,变量名不建议命名为 dict

def method_a():
    dict_1 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
    print(dict_1) # {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}

dict 方式

创建字典的另一种方法就是使用 dict 函数。Python 中的 dict 函数的作用实质上主要是将包含双值子序列的序列对象转换为字典类型,其中各双值子序列中的第1个元素作为字典的键,第2个元素作为对应的值,即双值子序列中包含了键值对信息。

所谓双值子序列,实际上就是一个二维数组,其中的每一个一维数组只包含两个元素,例如只包含两个元素的列表 ['name',Lily']、元组 ('age',18)、仅包含两个字符的字符串 ab 等。将字典中的键和值组织成双值子序列,然后将这些双值子序列组成序列,例如组成元组(['name','Lily'],('age',18),'ab'),再传入 dict 函数中,即可转换为字典类型,得到字典对象。

def method_b():
    dict_2 = dict([('id', '101'), ['name', '张三'], ['gender', '男'], ['age', '19']]) # 里边的[]和()没有区别
    dict_3 = dict(['ab', 'cd', 'ef'])
    print(dict_2) # {'id': '101', 'name': '张三', 'gender': '男', 'age': '19'}
    print(dict_3) # {'a': 'b', 'c': 'd', 'e': 'f'}

除了通过转换方式创建字典外,还可以直接向 dict 函数传入键和值进行创建,其中须通过 = 将键和值隔开。注意,这种创建方式不允许键重复,否则会返回错误,具体格式如下。

dict(key_1=value_1, key_2=value_2,…, key_n=value_n)

例如:

def method_c():
    dict_4 = dict(id='101', name='张三', gender='男', age=19)
    print(dict_4)  # {'id': '101', 'name': '张三', 'gender': '男', 'age': 19}

注意:使用 dict() 创建字典使用 dict(键=值),键的前后不需要加上引号。

键值对

字典是以键值对(key:value)为元素构成的集合,可以看成是一种特殊的集合,因此:

  1. 键值对是通过键(key)来标识的,要求唯一不重复。
  2. 键值对的排列是无序的,无法通过索引来访问键值对(但从3.6版本开始,字典开始是有序的,这是新的版本特征)。
  3. 对键的要求:唯一,并且必须是不可变数据类型,键一旦创建就不允许修改。
  4. 值可以是 Python 的任何数据类型,值可以修改、也可取重复值。

注意:

  1. 列表等序列类型通过索引访问元素。
  2. 字典允许通过键来访问对应的值。
  3. 而集合无法访问单个元素,只能整体访问。

字典的操作

提取字典元素

与序列类型不同,字典作为映射类型数据结构,并没有索引的概念,也没有切片操作等处理方法,字典中只有键和值对应起来的映射关系,因此字典元素的提取主要是利用这种映射关系来实现。

通过在字典对象后紧跟方括号 [ ] 包括的键可以提取相应的值,具体使用格式为字典[键]

def method_d():
    dict_5 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
    print(f'id:{dict_5['id']},name:{dict_5['name']},gender:{dict_5["gender"]},age:{dict_5["age"]}')

同时应注意,传入的键要存在于字典中,否则会返回一个错误。

def method_e():
    dict_6 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
    print(f'address:{dict_6['address']}')  # ❌ KeyError: 'address'

为避免出现上述传入键不存在而导致出错的现象,Python 提供了两种处理方法。

  1. 提取前使用 in 语句测试键是否存在

    错误主要是因为传入的键不存在而导致的,因此在传人键之前,尝试去检查字典中是否包含这个键;若不存在,则不进行提取操作。这种功能具体可以使用 in 语句来实现。

    def method_f():
        dict_7 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        flag_1 = 'address' in dict_7
        flag_2 = 'name' in dict_7
        print(f'address是否存在{flag_1},name是否存在{flag_2}')  # address是否存在False,name是否存在True
  2. 使用 get 函数获取

    字典方法 get 能够灵活地处理元素的提取,向 get 函数传人需要的键和一个代替值即可,无论键是否存在。若只传人键,当键存在于字典中时,函数会返回对应的值;当键不存在时,函数会返回 None,屏幕上什么都不显示。若同时也传入代替值,当键存在时,返回对应值;当键不存在时,返回这个传入的代替值,而不是 None

    def method_g():
        dict_8 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        print(f'id:{dict_8.get('id')},name:{dict_8.get('name')},address:{dict_8.get('address', '缺省值')},phone:{dict_8.get('phone')}') # id:1,name:张三,address:缺省值,phone:None

添加字典元素

添加字典元素也有两种方式。

  1. 使用键访问赋值增添

    利用字典元素提取方法传入一个新的键,并对这个键进行赋值操作,字典中会产生新的键值对。

    def method_h():
        dict_9 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        dict_9['address'] = '陕西西安'
        print(dict_9) # {'id': 1, 'name': '张三', 'gender': '男', 'age': 19, 'address': '陕西西安'}
  2. 使用 update 函数

    字典方法 update 能将两个字典中的键值对进行合并,传入字典中的键值对会复制添加到调用函数的字典对象中。若两个字典中存在相同键,传入字典中的键所对应的值会替换掉调用函数字典对象中的原有值,实现值更新的效果。

    def method_i():
        dict_10 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        dict_11 = {'id': 2, 'address': '陕西西安', 'phone': '13099998765'}
        # 将 dict_11 字典传入到 dict_10 中
        dict_10.update(dict_11) 
        print(dict_10)  # {'id': 2, 'name': '张三', 'gender': '男', 'age': 19, 'address': '陕西西安', 'phone': '13099998765'}
        print(dict_11)  # {'id': 2, 'address': '陕西西安', 'phone': '13099998765'}

删除字典元素

删除有四种方式实现。

  1. 使用 del 语句

    def method_j():
        dict_12 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        print(dict_12)  # {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        del dict_12['id']  
        del dict_12['address'] # ❌ KeyError: 'address'
        print(dict_12)  # {'name': '张三', 'gender': '男', 'age': 19}
  2. 使用 pop 函数

    pop 函数传入需要删除的键,则会返回对应的值,并在字典当中移除相应的键值对。若将函数返回的结果赋值给变量,就相当于从字典当中抽离出了值。

    def method_k1():
        dict_13 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        print(dict_13)  # {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        did = dict_13.pop('id')
        print(did) # 1
        print(dict_13)  # {'name': '张三', 'gender': '男', 'age': 19}
  3. 使用 popitem 函数

    popitem() 方法返回并删除字典中的最后一对键和值。如果字典已经为空,却调用了此方法,就报出 KeyError 异常。

    def method_k2():
        dict_13 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        print(dict_13)  # {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        item = dict_13.popitem()
        print(item)  # ('age', 19)
        print(dict_13)  # {'id': 1, 'name': '张三', 'gender': '男'}

    注意:在 Python3.7 之前,popitem() 方法删除并返回任意插入字典的键值对。

  4. 使用 clear 函数

    clear 函数会删除字典中的所有元素,最终会返回一个空字典。

    def method_l():
        dict_14 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        print(dict_14)  # {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
        dict_14.clear()
        print(dict_14)  # {}

修改字典元素

修改字典元素,就是重新赋值的过程。因为字典元素中 key 不允许重复,如果重复,后边的会覆盖前边的值。我们可以利用这一特性实现对字典元素的修改。

字典[key] = new_value

字典元素信息

字典可以看成是一个集合,它的键也可以看成是一个集合,同理值也是一个集合。那么,我们就要有相应的函数获取到它们。

字典方法中有3种方式可以用于提取键值信息:

  • keys:用于获取字典中的所有键。
  • values:用于获取字典中的所有值。
  • itmes:得到字典中的所有键值对。

这3种方式所返回的结果是字典中键、值或键值对的迭代形式,都可以通过 list 函数将返回结果转换为列表类型,同时可以配合 in 的使用,判断值和键值对是否存在于字典当中。

def method_m():
    dict_15 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
    dict_key = dict_15.keys()
    dict_val = dict_15.values()
    dict_items = dict_15.items()
    print(dict_key)  # dict_keys(['id', 'name', 'gender', 'age'])
    print(dict_val)  # dict_values([1, '张三', '男', 19])
    print(dict_items)  # dict_items([('id', 1), ('name', '张三'), ('gender', '男'), ('age', 19)])
    for k in dict_key:
        print(k)
    for v in dict_val:
        print(v)
    for k,v in dict_items:
        print(f'key:{k},value:{v}')

字典的遍历

遍历所有的键和值,items() 可以将每一个键值对转为为元组的形式。

def method_n():
    dict_16 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
    for k, v in dict_16.items():
        print(k, v)

常用函数

操作函数 描述
len(dict) 字典 dict 的元素个数(长度)
str(dict) 字典 dict 的字符串形式
min(dict) 字典 dict 中键的最小值
max(dict) 字典 dict 中键的最大值
def method_o():
    dict_17 = {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}
    print(max(dict_17))  # name
    print(min(dict_17))  # age
    print(len(dict_17))  # 4
    print(str(dict_17))  # {'id': 1, 'name': '张三', 'gender': '男', 'age': 19}

字典在 Python 编程中提供了一个强大的工具,用于处理键值对数据的存储、快速查找和数据映射等任务。通过结合使用字典的各种操作,我们可以有效地解决许多常见的编程问题。字典的独特特性使它在处理无序数据和保证键的唯一性方面尤为出色。

By admin

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注