相关资料
可迭代对象
在Python中,可迭代对象是指可以使用for
循环进行迭代的对象.它们可以是序列类型(例如字符串,列表或元组)以及其他实现了__iter__
方法的对象.
以下是一些常见的Python可迭代对象:
- 字符串:字符串可以逐个字符地进行迭代.
string = "Hello"
for char in string:
print(char)
- 列表和元组:列表和元组中的每个元素都可以被迭代.
my_list = [1, 2, 3]
my_tuple = (4, 5, 6)
for item in my_list:
print(item)
for item in my_tuple:
print(item)
- 字典:默认情况下,迭代字典会返回其键.
my_dict = {'a': 1, 'b': 2, 'c': 3}
for key in my_dict:
print(key)
如果想要迭代字典的值,可以使用values()
方法:
for value in my_dict.values():
print(value)
如果想要同时迭代字典的键和值,可以使用items()
方法:
for key, value in my_dict.items():
print(key, value)
- 文件对象:使用
open()
函数打开文件后,返回的文件对象可以被迭代按行读取.
with open('file.txt', 'r') as file:
for line in file:
print(line)
除了以上这些常见的可迭代对象,您也可以自定义类,并实现一个名为__iter__
的方法来使其成为可迭代对象.
命名
在Python中,有一些命名规则和约定以确保代码的可读性和一致性.以下是一些常见的Python命名规则:
变量名和函数名使用小写字母,单词之间使用下划线 "_" 分隔.例如:num_students,calculate_average.
类名使用驼峰命名法,每个单词的首字母大写,并且不使用下划线.例如:Person,StudentRecord.
常量名全大写,并且单词之间使用下划线分隔.例如:MAX_SIZE,PI.
私有变量和方法名使用下划线开头,表示这些成员应该被视为私有,不应该从外部直接访问.例如:_secret_key.
模块名使用全小写字母,并且避免使用下划线分隔.例如:math,random.
如果函数名和内置函数或关键字重名,应该在名称后面添加一个下划线以避免冲突.例如:print_.
尽量使用具有描述性和有意义的名称,以便代码可读性强,并且易于理解和维护.
这些命名规则是Python社区的共识,遵循这些规则可以使你的代码更具可读性,并且与其他Python代码更加一致.
bug
bug的分类
- 粗心导致的语法错误(SyntaxError)
- 冒号
- 缩进
- 中文符号
- 字符串的拼接把字符串和数字拼接在一起
- 未定义变量
- 比较和赋值运算符弄混
- 知识点不熟悉导致的错误(多练习)
- 索引越界IndexError
- 函数,方法使用有误
- ......
- 思路不清导致的问题
- 解决方案:
- 使用print()函数
- 使用#暂时注释部分代码
- 逐层分析
- 解决方案:
- 被动掉坑:代码逻辑没错,由于用户的错误操作或者一些"例外情况"导致程序崩溃
- python内置的异常处理机制,可以在异常出现时即时捕获然后内部消化,让程序继续进行,使用
try-except
结构
- python内置的异常处理机制,可以在异常出现时即时捕获然后内部消化,让程序继续进行,使用
python的异常处理机制
try-except
结构
在异常出现时即时捕获然后内部消化,让程序继续进行
- except可以使用多个
- 捕获异常的顺序按照先子类后父亲类的顺序,为了避免遗漏可能出现的异常,可以在最后增加BaseException(最大)
try:
n1 = int(input('请输入一个整数'))
n2 = int(input('请输入另一个整数'))
result= n1 / n2
print('结果为', result)
except ZeroDivisionError:
print('除数不能为0')
except xxxxx:
xxxxxx
except BaseException as e:
print(e)
try-except-else
结构
如果try没有出现异常,则执行else块,如果try中出现异常,执行except块
try-except-else-finally
结构
finally块无论是否发生异常都会执行,常用于释放try块中申请的资源
try:
...
...
...
except BaseException as e:
....
print(e)
else:
...
...
finally:
...
....
traceback
模块
使用traceback
模块打印异常信息,可以用来写入日志
import traceback
try:
print(1 / 0)
except:
traceback.print_exc()
python的常见异常类型
- ZeroDivisionError 除(或取模)零(所有数据类型)
- IndexError 序列中没有此索引
- KeyError 映射中没有这个键
- NameError 未声明/初始化对象(没有属性)
- SyntaxError 语法错误
- ValueError 传入无效的参数
Pycharm开发环境的调试
- 断点(红点)
- 程序运行到此处暂时挂起,停止运行.此时可以详细观察程序的运行情况,方便做出进一步的判断
- 进入调试视图(小虫子)
- 进入调试工具的三种方式
- 单击工具栏上的按钮
- 右键单击编辑区,点击debug模块名
- 快捷键shift + F9
- 进入调试工具的三种方式
python的基础
python的简介
Python是一种高级,通用,解释型的编程语言,具有简洁,易读,易学和强大的功能.它由Guido van Rossum于1991年创建,并且现在已经成为最受欢迎的编程语言之一.
下面是 Python 的一些重要特点:
简单易学: Python的语法简洁且易于理解,使其成为学习编程的理想选择.它使用明显的代码风格,注重可读性和易于维护.
高级语言: Python提供了大量的高级数据结构,如列表,元组和字典,以及内部支持的大量库和模块,使得在Python中开发功能强大的应用程序变得简单.
运行速度: Python通常被称为一种解释型语言,因为它是通过解释器执行代码.虽然Python相对于诸如C++或Java等编译型语言来说运行速度较慢,但是由于其代码简洁,可以快速开发出有效的解决方案.
跨平台: Python可以在多个操作系统上运行,包括Windows,Linux和MacOS等.这意味着你可以在不同的平台上使用相同的Python代码,而不需要对其进行修改.
大量的库和框架: Python拥有庞大的生态系统,提供了许多第三方库和框架,支持各种任务,如Web开发,科学计算,数据分析,机器学习等.其中一些库和框架包括NumPy,Pandas,Django和TensorFlow等.
强大的社区支持: Python拥有一个庞大的开发者社区,这意味着你可以轻松地获得帮助,解决问题,并与其他开发者分享你的代码和想法.
Python在多个领域都有广泛的应用,包括Web开发,数据分析,人工智能,科学计算,物联网等.由于其易用性和强大的功能,它已经成为许多开发者的首选语言.
总之,Python是一种功能强大且易于学习的编程语言,适用于各种任务,从简单的脚本到复杂的应用程序开发都能胜任.
安装python的解释器和开发环境
python是一种解释型,交互式,面向对象式的编程语言
解释型语言是一种编程语言,它通过逐行解释源代码来执行程序.在解释型语言中,源代码在运行时逐行翻译为机器语言,并立即执行相应的指令.解释型语言不需要编译成可执行文件,而是使用解释器逐行解释并执行代码.一些常见的解释型语言包括Python,JavaScript和Ruby.
交互式语言是一种编程语言,它允许用户直接与计算机进行交互.在交互式语言中,用户可以在运行时输入代码,并立即查看执行结果.用户可以一边编写代码,一边运行并测试代码的效果.通常,交互式语言提供一个命令行界面或集成开发环境(IDE)来实现交互性.例如,Python的交互式模式提供了一个交互式Shell,可以直接输入代码并查看结果.
面向对象是一种编程范式,通过建立对象来描述程序的结构和行为.在面向对象编程中,对象是程序的基本组成单位,它包含了数据和用于操作数据的方法.对象可以相互进行数据和消息传递,从而实现程序的功能.面向对象编程的主要概念包括封装,继承和多态.封装使得对象的内部状态对外部是隐藏的,继承允许对象通过继承现有对象的属性和方法来扩展功能,而多态允许不同对象对相同消息作出不同响应.常见的面向对象编程语言包括Java,C++和Python.
在安装python解释器后,它在开始菜单的目录里会有四个文件,分别是IDLE(python自带的简单开发环境),python(交互式命令行程序),Manuals(官方技术文档,包含api等信息)和Modules Docs(已安装的模块文档)
API代表Application Programming Interface(应用程序接口),是一组定义了软件组件或系统之间交互和通信的规范.它允许不同的软件应用程序之间共享数据和功能,促进了软件的集成和互操作性.
API定义了请求和响应的数据格式和通信协议.通过API,开发人员可以访问和操作操作系统,库,框架,服务或其他软件组件的功能.API可以用于不同编程语言,平台和技术栈. API可以以不同形式存在,如:
Web API:通过互联网协议(如HTTP)提供的接口,允许通过Web进行通信. 库API:由软件库提供的一组函数,类或对象,供开发人员在自己的应用程序中使用. 操作系统API:操作系统提供的一组函数和服务,允许应用程序与操作系统进行交互. 第三方API:由第三方提供的API,允许开发人员在自己的应用程序中利用第三方服务的功能.
API的好处包括: 促进软件集成:通过API,不同的应用程序可以集成和互操作,共享数据和功能. 提高开发效率:开发人员可以利用现有的API,而无需从头开始编写所有代码. 降低软件复杂性:通过将功能模块化和抽象化,API可以简化软件开发过程. 促进创新:开放的API可以使其他开发人员构建在其上的应用程序或服务,从而推动创新和生态系统的发展.
总之,API是一种软件组件之间进行通信和共享功能的方式,提供一种标准化的接口,以促进软件集成和开发的效率.
建议使用第三方开发环境pycharm
python的数据类型和变量
整数类型
int(integer),可以表示正数负数和0,对于不同进制的表示,默认为十进制
在Python中,整数可以表示为不同进制类型的数.以下是几种常见的进制类型及其表示方式:
十进制(Decimal):默认情况下,Python中的整数是十进制的.例如:
num = 10
二进制(Binary):可以通过在数字前加上
0b
或0B
前缀来表示二进制数.例如:num = 0b10
表示二进制数2.八进制(Octal):可以通过在数字前加上
0o
或0O
前缀来表示八进制数.例如:num = 0o10
表示八进制数8.十六进制(Hexadecimal):可以通过在数字前加上
0x
或0X
前缀来表示十六进制数.例如:num = 0x10
表示十六进制数16.
你可以使用内置函数bin()
,oct()
和hex()
来将十进制数转换为对应的二进制,八进制和十六进制表示形式.例如:
num = 10
print(bin(num)) # 输出:0b1010
print(oct(num)) # 输出:0o12
print(hex(num)) # 输出:0xa
需要注意的是,无论你使用什么进制表示数,当你打印输出时,Python会默认将其转换为十进制形式.
浮点数类型
浮点数由整数部分和小数部分组成.
在Python中,浮点类型是一种用于表示小数的数据类型.它可以表示带有小数点的数字,并允许进行浮点数运算.Python使用IEEE 754标准来表示浮点数,并提供了一些内置函数和方法来处理浮点数.
要声明一个浮点数,只需直接输入它即可,例如:
x = 3.14
y = 2.71828
Python还支持科学计数法来表示很大或很小的浮点数,使用小写或大写的 "e" 来表示乘以 10 的幂.例如:
a = 1e-5 # 表示0.00001
b = 1.23e6 # 表示1230000.0
可以使用各种算术运算符(如加法,减法,乘法和除法)对浮点数进行运算.但是需要注意,在浮点数运算中可能会出现舍入误差.此时可以选择导入模块来解决.
from decimal import Decimal
print(Decimal('1.1' + '2.2'))
浮点数还具有一些内置函数和方法,例如:
round(x, n)
: 将浮点数 x 四舍五入至 n 位小数.math.floor(x)
: 返回不大于浮点数 x 的最大整数.math.ceil(x)
: 返回不小于浮点数 x 的最小整数.math.trunc(x)
: 返回浮点数 x 的整数部分.
这些是Python中浮点数的基本概念和操作.通过使用浮点数,您可以进行更精确的数值计算和表示.
布尔类型
在Python中,布尔类型(bool)是一种基本的数据类型.它只有两个可能的值:True(真)和False(假).布尔类型用于逻辑判断和条件表达式中,非常常用.
对于一些返回值为布尔类型的函数和方法可以在条件判断中简化代码.
# 暂时还没想好例子
布尔类型的值可以通过不同的方式获得.例如,比较运算符(如==,>,<等)可以用来比较两个值,结果将返回True或False.在条件语句中,根据条件成立与否来执行不同的代码块.
以下是一些示例,演示了在Python中使用布尔类型的常见情况:
x = 5
y = 10
# 使用比较运算符
print(x == y) # False
print(x < y) # True
# 使用逻辑运算符
print((x == 5) and (y == 10)) # True
print((x == 5) or (y == 5)) # True
print(not (x == 5)) # False
# 使用条件语句
if x < y:
print("x小于y")
else:
print("x大于等于y")
以上示例显示了如何使用布尔类型进行比较,逻辑运算和条件语句.布尔类型在计算机编程中非常有用,用于决策和控制程序流程.
布尔类型可以转化为整数,True对应1,False对应0,并且它可以参与运算
print(True + 1)
字符串类型
基本内容
字符串是一种基本数据类型,又被称为不可变的字符序列,可以用单引号,双引号和三引号来定义 单引号和双引号定义的字符串必须在一行,三引号定义的字符串可以分布在连续的多行
'helloworld'
"helloworld"
'''hello
world'''
字符串的驻留机制
仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串的驻留池中,python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时不会开辟新空间,而是吧该字符串的地址赋给新创建的变量
Python中的字符串驻留机制是一种优化策略,旨在节省内存和提高性能.以下是字符串驻留机制的作用和优势:
- 字符串共享:字符串驻留机制通过让多个相同内容的字符串指向同一个内存地址,实现字符串的共享.这意味着当多个变量引用相同的字符串时,它们实际上引用的是同一个对象,从而节省了内存空间.
- 字符串比较效率高:由于字符串驻留机制的存在,相同内容的字符串实际上是同一个对象,因此比较字符串时可以直接比较它们的内存地址,而无需逐个字符进行比较.这样可以提高字符串比较的效率.
- 字符串常量池:Python将长度为1的字符串和某些简单字符串(如整数,浮点数,空字符串等)保存在字符串常量池中.这些字符串具有固定的内存地址,与其他代码执行无关,可以直接引用.这在某些情况下可以加速字符串的创建和比较操作.
需要注意的是,字符串驻留机制只适用于较短的字符串,具体的实现方式也可能因Python版本和具体的情况而异.对于较长或动态生成的字符串,字符串驻留机制可能没有明显的优势,甚至会带来额外的开销.因此,在编写代码时,应根据具体情况选择是否进行字符串驻留.
驻留机制的几种情况(交互模式)
- 字符串的长度为0或1时
- 符合标识符的字符串(字母数字下划线)
- 字符串只在编译的时候驻留,而非运行时
a = 'abcx'
b = 'ab' + 'c'
c = ''.join(['ab','c'])
a is b # True
a is c # False
# b的值在运行之前就已经连接完毕,而c的值是在运行时连接的,没有产生驻留机制
- [-5, 256]之间的整数数字
sys中的intern方法可以强制使两个相同的字符串指向同一个对象
pycharm对字符串进行了优化处理(相同的字符串强制指向同一个地址)
tip:拼接字符串和修改字符串是比较影响性能的,因为它会创建新的字符串占用内存,所以在需要进行字符串拼接的时候建议采用str类型的join()方法,而非+,因为join()方法是先计算所有字符串中的长度,然后再拷贝,只new一次对象,效率要比+高
字符串的常用操作
查询操作
查询方法
index()
查找子串substr
第一次出现的位置,如果查找的字串不存在时,则抛出ValueError
rindex()
查找子串substr
最后一次出现的位置,如果查找的字串不存在时,则抛出ValueError
find()
查找子串substr
第一次出现的位置,如果查找的字串不存在时,则返回-1rfind()
查找子串substr
最后一次出现的位置,如果查找的字串不存在时,则返回-1
字串substr放在小括号里,上述方法的返回值是索引
大小写转换操作
大小写转换方法
upper()
把字符串中的所有字符都转成大写字母lower()
把字符串中的所有字符都转成小写字母swapcase()
把字符串中的所有小写字母都转成大写字母,把字符串中的所有大写字母都转成小写字母capitalize()
把第一个字符转换为大写,其余字母转换为小写title()
把每个单词的第一个字符转换为大写,把每个单词的剩余字符转换为小写
上述方法会产生新的字符串对象
内容对齐操作
字符串对齐方法参数放在括号内,用逗号隔开
center()
居中对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数可选,默认是空格,如果设置宽度小于字符串宽度则返回原字符串ljust()
左对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数可选,默认是空格,如果设置宽度小于字符串宽度则返回原字符串rjust()
右对齐,第一个参数指定宽度,第二个参数指定填充符,第二个参数可选,默认是空格,如果设置宽度小于是指宽度则返回原字符串zfill()
右对齐,左边用0填充,该方法只接受一个参数,用于指定字符串的宽度,如果设置宽度小于字符串宽度则返回原字符串
劈分操作
字符串的劈分方法
split()
从字符串的左边开始劈分,默认的劈分字符是空格字符串,通过参数sep指定劈分的分隔符,通过参数maxsplit指定最大拆分次数.如果给定一个正整数,则最多只会拆分出该数量的子字符串(以分隔符为分界线分割),剩余的子字符串会单独作为一部分rsplit()
从字符串的右边开始劈分,默认的劈分字符是空格字符串,通过参数sep指定劈分的分隔符,通过参数maxsplit指定最大拆分次数.如果给定一个正整数,则最多只会拆分出该数量的子字符串(以分隔符为分界线分割),剩余的子字符串会单独作为一部分 example:
date = "2022-01-01"
year, month, day = date.split('-') # 这样赋值没怎么用过
print(year, month, day)
判断操作
判断字符串的方法
isidentifier()
判断指定的字符串是不是合法的标识符isspace()
判断指定的字符串是不是全部由空白字符组成(回车,换行,水平制表符)isalpha()
判断指定的字符串是不是全部由字母组成isdecimal()
判断指定的字符串是不是全部由十进制的数字组成isnumeric()
判断指定的字符串是不是全部由数字组成(数字的类型很多)isalnum()
判断指定的字符串是不是全部由字母和数字组成
上述方法返回的值为布尔类型
替换和合并操作
replace()
第一个参数指定被替换的子串,第二个参数指定替换子串的字符串,该方法返回替换后得到的字符串,替换前的字符串不发生改变,调用该方法时可以通过第三个参数指定最大替换次数 join()
将列表或元组中的字符串合并成一个字符串,并返回 (用起来不太一样,下面是示例)
字符串连接符.join(可迭代对象)
比较操作
- 运算符:>,<,>=,<=,==,!=
==
比较的是value,is
比较的是id
- 比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符,依次比较下去,直到两个字符串的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串的所有后续字符将不再被比较
- 比较原理:两个字符比较时,比较的是其ordinalvalue(原始值),调用内置函数ord()可以得到指定字符的ordinalvalue.与内置函数ord()对应的时内置函数chr(),调用时指定ordinalvalue可以得到对应的字符
切片操作
切片操作将产生新的对象,因为字符串是不可变类型,不具备增删改等操作
在Python中,切片是一种用于从序列(例如列表,元组,字符串等)中获取子序列的操作.切片操作的语法如下:
sequence[start:stop:step]
start
:起始索引,表示切片起始位置的索引值(包含在切片结果中).stop
:结束索引,表示切片结束位置的索引值(不包含在切片结果中).step
:步长,表示切片的间隔,默认为1.
下面是一些切片操作的示例:
- 获取列表中的子列表:
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sub_list = my_list[2:6] # 获取索引2到索引5的子列表
print(sub_list) # 输出:[2, 3, 4, 5]
- 从字符串中提取子串:
my_string = "Hello, World!"
sub_string = my_string[7:12] # 获取索引7到索引11的子串
print(sub_string) # 输出:World
- 使用步长获取每隔一定间隔的元素:
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sub_list = my_list[1:9:2] # 从索引1到索引8,每隔2个元素获取一次
print(sub_list) # 输出:[1, 3, 5, 7]
需要注意的是,切片索引是以0为起始的,并且切片操作不会改变原始序列,而是生成一个新的切片对象.
格式化操作
格式化字符串的两种方式
- %做占位符(包含宽度和精度的控制)
- %s是字符串
- %i或%d是整数
- %f是浮点数
'我的名字叫:%s,今年%d岁了' % (name, age) # 前面是定义的格式化字符串,% 是固定符号,(name,age)是实际值
print('%10d' % 99) # 10表示的是宽度
print('%.3f' % 3.1415926) # .3表示的是小数点后三位
print('%10.3f' % 3.1415926) # 宽度是10,小数点后三位
- {}做占位符(包含宽度和精度的控制)
'我的名字叫:{0},今年{1}岁了,我真的叫{0}'.fomat(name, age) # 利用了fomat()方法
print('{0:.3}'.format(3.1415926)) # .3表示的是一共是三位数
print('{0:.3f}'.format(3.1415926)) # .3f表示的是三位小数
print('{0:10.3f}'.format(3.1415926)) # 10.3f表示的是宽度是10,精度是三位小数
- f-string
print(f'我叫{name},今年{age}岁')
下面的内容来自GPT4.0
在Python中,格式化字符串有多种方法.以下是几种常用的方法:
- 使用百分号(%)格式化字符串:这种方法使用百分号作为占位符,然后使用一个元组将要替换的值传递给百分号.
pythonname = "Alice" age = 25 print("My name is %s and I am %d years old." % (name, age))
- 使用字符串的
format()
方法:这种方法使用大括号作为占位符,并使用format()
方法传递要替换的值.
pythonname = "Alice" age = 25 print("My name is {} and I am {} years old.".format(name, age))
- 使用f-strings(格式化字符串字面值):这是Python 3.6及更高版本引入的一种方便的字符串格式化方法.在字符串前面加上字母"f",然后在大括号中使用表达式来替换变量的值.
pythonname = "Alice" age = 25 print(f"My name is {name} and I am {age} years old.")
这些都是Python中常用的格式化字符串的方法.您可以根据自己的喜好和要求选择使用哪种方法.
字符串的编码转换
以下内容来自GPT4.0
在Python中对字符串进行编码转换有一些常见的原因和用途:
- 支持不同字符集:不同的字符集或编码方式可以包含不同的字符和符号.当处理多语言文本时,可能需要将字符串从一个字符集转换为另一个字符集,以确保正确的显示和处理.
- 数据传输:在数据传输过程中,特别是在不同系统之间传输数据时,可能需要对字符串进行编码转换,以确保数据在不同系统间正确地解析和处理.
- 文件操作:在读取和写入文件时,需要确保文件中的字符串编码和程序的默认编码一致.如果文件编码与程序所需的编码不匹配,可能会导致字符串解析错误或乱码.
- 数据存储和数据库操作:在将字符串存储在数据库或其他数据存储介质中时,可能需要对字符串进行编码转换,以确保数据的一致性和正确性.
- 文本处理和分析:在文本处理和分析任务中,可能需要对字符串进行编码转换以匹配某些算法或模型的要求.例如,某些自然语言处理库可能只接受特定编码的字符串作为输入.
总而言之,对字符串进行编码转换可以确保数据的正确交互和处理,同时也能使字符集的多样性被适当地处理和呈现.
编码和解码的方式
- 编码:将字符串转为二进制数据(bytes),调用encode()方法
- 解码:将bytes类型的数据转换成字符串类型,调用decode()方法
# 编码
s = '天涯共此时'
print(s.encode(encoding='GBK')) # 在GBK这种编码格式中,一个中文占两个字节
print(s.encode(encoding='UTF-8')) # 在UTF-8这种编码格式中,一个中文占三个字节
# 解码
byte = s.encode(encoding='GBK')
print(byte.decode(encoding='GBK'))
数据类型的转换
主要用到的函数有:(下面三者可以互相转换)
str()
将其他数据类型转化为字符串int()
将其他数据类型转化为整数
文字类和小数类字符串无法转为整数类型,浮点数转为整数会将小数部分抹去只取整数部分
float()
将其他数据类型转化为浮点数
文字类字符串无法转为浮点数,整数转化为浮点数,末尾加上.0
在Python中,数据类型转换是将一个数据类型转换为另一个数据类型的过程.这是因为不同的数据类型具有不同的特性和用途,有些操作只能在特定的数据类型上执行.数据类型转换可以帮助我们在不同数据类型之间进行无缝的转换,使得我们能够在不同的场景中使用适当的操作.
下面是一些常见的数据类型转换及其原因和用法的例子:
- 字符串转换为整数或浮点数:当我们需要将一个数字表达为字符串时,我们可以使用整数或浮点数数据类型.这对于执行数值运算或比较操作非常有用.
num_str = "10" # 字符串类型
num_int = int(num_str) # 转换为整数类型
num_float = float(num_str) # 转换为浮点数类型
- 整数或浮点数转换为字符串:当我们需要将一个数字转换为字符串时,我们可以使用字符串数据类型.这对于将数字与其他文本进行拼接或输出到文件中非常有用.
num_int = 10 # 整数类型
num_float = 3.14 # 浮点数类型
num_str1 = str(num_int) # 转换为字符串类型
num_str2 = str(num_float) # 转换为字符串类型
- 列表,元组和集合之间的转换:列表,元组和集合是用于存储多个元素的数据类型,但它们之间有着不同的特性.有时候,我们需要在这些数据类型之间进行转换,以便适应不同的场景和操作.
my_list = [1, 2, 3] # 列表类型
my_tuple = tuple(my_list) # 转换为元组类型
my_set = set(my_list) # 转换为集合类型
- 布尔类型的转换:布尔类型代表真(True)或假(False)的值.有时候,我们需要将其他数据类型转换为布尔类型,以便进行条件判断或逻辑运算.
num = 10 # 整数类型
bool_val = bool(num) # 转换为布尔类型
数据类型转换是Python中常用的操作之一,可以帮助我们处理和操作不同类型的数据.在进行数据类型转换时,需要注意数据的有效性和精度,以避免出现错误或意外的结果.
变量
标识符:给变量,函数,类,模块和其他对象所起的名字,它们的命名有以下规则:
- 可以使用字母,数字,下划线
- 不能以数字开头
- 不能是保留字
- 严格区分大小写 保留字:被赋予了特定的意义,这些单词给任意对象取名的时候都不能使用,可以使用如下代码输出保留字(用错了会报错,可以不记)
import keyword
print(keyword.kwlist)
['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']
变量的定义与运用
变量是内存里一个带标签的盒子,由标识,类型和值组成
- 标识:表示对象所储存的内存地址,可以使用内置函数
id()
来获取 - 类型:表示对象的数据类型,可以使用内置函数
type()
来获取(强类型语言) - 值:表示对象所存储的具体数据,可以使用内置函数
print()
将值打印输出
name = 'Marry' # name是变量名,=是赋值运算符,'Marry'是值
变量在多次赋值后,变量名会指向新的内存空间(原本的空间成为了内存垃圾,会由垃圾回收机制回收)
基本的运算符和表达式
Python中的基本运算符和表达式包括:
- 算术运算符:用于执行基本的数学运算,例如加法(+),减法(-),乘法(*),除法(/),取余(%)和取整除(//),幂运算符(**).
在算术运算符中,整除服从 一正一负向下取整 的规则
取余服从公式余数 = 被除数 - 除数 * 商
加减乘除和整除是标准算数运算符
比较运算符:用于比较两个值,并生成一个布尔值(True或False).例如等于(==),不等于(!=),大于(>),小于(<),大于等于(>=)和小于等于(<=).
逻辑运算符:用于对布尔值进行逻辑操作.例如与(and),或(or)和非(not).
- 当进行运算时,
not
>`and和or - python的逻辑运算符具有短路求值的特性,使用and运算符如果第一个操作值为False则不会进行下一步计算.当使用or计算符时,如果第一个操作数为True,将不会计算第二个操作数.
- and和or如果结果为真,则返回终止运算时对应的值 逻辑运算符的顺序:not>and>or
在Python中,逻辑运算符用于对布尔型数据进行操作和组合.Python提供了三种逻辑运算符:and(与),or(或)和not(非).下面对每个逻辑运算符进行详细介绍:
- and(与):当所有操作数都为True时,返回True;否则返回False.它可以用于连接多个条件,只有当所有条件都为True时整个表达式才为True.
例如:
a = True
b = False
c = a and b
print(c) # 输出:False
- or(或):当至少一个操作数为True时,返回True;如果所有操作数都为False,则返回False.它可以用于连接多个条件,只要有一个条件为True,整个表达式就为True.
例如:
a = True
b = False
c = a or b
print(c) # 输出:True
- not(非):用于对一个布尔值取反.如果操作数为True,则返回False;如果操作数为False,则返回True.
例如:
a = True
b = not a
print(b) # 输出:False
逻辑运算符可以与比较运算符结合使用,用于构建复杂的逻辑表达式.
例如:
a = 5
b = 10
c = 7
d = (a > b) and (b > c) # False and True,因此整个表达式为False
print(d) # 输出:False
此外,逻辑运算符具有短路求值的特性.当使用and运算符时,如果第一个操作数为False,将不会计算第二个操作数,因为整个表达式已经为False.类似地,当使用or运算符时,如果第一个操作数为True,将不会计算第二个操作数,因为整个表达式已经为True.
- 赋值运算符:用于给变量赋值.例如等号(=),加等于(+=),减等于(-=),乘等于(*=)和除等于(/=).
赋值运算符的执行顺序是从右往左
a = b = c = 20 # 支持链式赋值
a, b, c = 10, 20, 30 # 支持系列解包赋值,该赋值方式遵循顺序赋值,要求等号左右数量相同,常用于变量的交换(不使用中间变量)
- 位运算符:用于对二进制数(要先转化为二进制数)进行位操作.例如按位与(&),按位或(|),按位异或(^),按位取反(~),左移(<<)和右移(>>).
位运算符的具体内容
位运算符是一组用来进行二进制位级操作的运算符.它们作用于整数类型的数据,将数字视为二进制表示,并对对应的二进制位进行操作.以下是一些常用的位运算符:
- 按位或(|):对两个操作数的每个二进制位执行逻辑或操作,只要两个相应位中的一个为1,结果位就为1.
- 按位异或(^):对两个操作数的每个二进制位执行逻辑异或操作,当两个相应位不同时,结果位为1,否则为0.
- 按位取反(~):对操作数的每个二进制位执行逻辑非操作,将1变为0,将0变为1.
- 左移(<<):将操作数的二进制表示向左移动指定的位数,右侧空出的位用0填充.
- 右移(>>):将操作数的二进制表示向右移动指定的位数,左侧空出的位用符号位(对于有符号整数)或0(对于无符号整数)填充.
这些位运算符可以用于各种目的,例如掩码操作,解决位级问题,对图像进行处理等.它们在一些特定的编程领域和底层操作中具有广泛的应用.
成员运算符:用于测试序列中是否包含特定的值.例如in和not in.
身份运算符:用于比较对象的内存地址.例如is和is not.
这些运算符和表达式是在Python中进行常见计算和操作的基础,可以根据具体的需求和上下文使用. 运算符的优先级
在Python中,不同运算符有不同的优先级和结合性.以下是常见的Python运算符按优先级从高到低的顺序:
- 括号:在括号中的表达式具有最高的优先级,可以用来控制运算顺序.
- 幂运算符:使用 ** 进行幂运算,例如
2 ** 3
表示2的3次方. - 乘法,除法和取模:使用 * 表示乘法,/ 表示除法,% 表示取模(取余数).
- 加法和减法:使用 + 表示加法,- 表示减法.
- 比较运算符:例如 <,>,<=,>=,==,!= 等,用于比较两个值之间的关系.
- 逻辑运算符:并且运算符 and,或运算符 or,非运算符 not,用于组合和操作布尔值.
- 赋值运算符:例如 =,+=,-=,*=,/= 等,用于赋值操作.
- 位运算符:例如按位与 &,按位或 |,按位异或 ^,按位取反 ~ 等.
- 成员运算符:例如 in,not in,用于检查值是否存在于序列中.
- 身份运算符:例如 is,is not,用于比较两个对象是否是同一个对象.
- 扩展语法:例如 f(x) 表示函数调用,x[y] 表示索引,x.y 表示属性访问.
请注意,可以使用括号来明确指定运算的顺序,并且在同一优先级的运算符中,从左到右进行计算.如果对运算符顺序有疑问,最好使用括号来明确表达式的意图.
注释
在Python中,注释可以用来在代码中添加说明和解释,提高代码的可读性和可维护性.Python支持两种类型的注释:单行注释和多行注释.
- 单行注释:使用井号符号(#)开头,用于在一行代码的尾部添加注释.
例如:
# 这是一个单行注释
print("Hello, World!") # 输出"Hello, World!"
- 多行注释:使用三个单引号(''')或三个双引号(""")包围注释内容,可以用于多行注释.
例如:
'''
这是一个多行注释
可以有多行内容
'''
或者:
"""
这也是一个多行注释
可以有多行内容
"""
请注意,Python解释器在运行代码时会忽略注释部分,注释不会被执行.
使用注释时应注意以下几点:
- 注释应该是清晰,简洁且易于理解的.
- 注释应该描述代码的逻辑,功能,输入和输出等信息.
- 避免在代码中添加过多无用的注释,只添加有实际意义的注释.
流程控制
(之后想办法把流程图画出来) 1996年,科学家证明了:任何简单或复杂的算法都可以由顺序结构,选择结构和循环结构三种基本结构组合而成 顺序结构:从上到下顺序的执行代码中间没有任何判断和跳转,知道程序结束 选择结构:程序根据判断条件的布尔值选择性的执行部分代码,明确的让计算机知道在什么条件下该做什么 循环结构:在满足条件的情况下反复做一件事
对象的布尔值:在python中一切皆对象,所有的对象都有一个布尔值,可使用bool()
来获取,这些对象的布尔值为False
- False
- 数值0
- None
- 空字符串,列表,元组,字典,集合
条件语句
- 单分支结构 如果..., 就...
if (条件表达式):
条件执行体
- 双分支结构 如果..., 就...,不满足,就...
if (条件表达式1):
条件执行体1
else:
条件执行体2
- 多分支结构(尽量使用多分支结构减少判断的次数)
if ...1: # 条件1满足则只执行条件执行体1
....1
elif ...2: # 在不满足条件1的前提下,确认是否符合条件2,如果满足则执行条件执行体2
....2
elif ...3: # 按照上述规律递推,只在上述的条件均不满足才会到下一个判断
....3
...... # 可能有n个
else: # 可写可不写,针对于上述条件都不满足的情况
....n+1
- 嵌套if
if ...: #外
if ...: #内
...
else:
...
else:
...
- 三元操作符
a = x if 条件 else y # 在同一句中完成条件判断和赋值
if 条件: # 与上一句话中作用相同
a = x
else:
a = y
循环语句
- while循环
while ...: # 满足条件进入循环,不满足退出循环
.... # 循环体
else:
....
可以使用else语句,则在while循环中,除非遇到break,否则在循环结束后运行else语句的条件执行体
和if的区别:if是判断一次执行一次,while是判断N+1次,条件为True执行N次,第N+1次为False,退出循环
执行流程
四步循环法:1.初始化变量 2.条件判断 3.条件执行体 4.改变变量(要注意这其中的变量是同一个变量)
可以使用while进入死循环,占用cpu时间
while True:
pass # 仅仅占位不做事
- for - in 循环
for i in range(0, 9, 1): # i是自定义变量,in表达的含义是在可迭代对象中依次取值,又称为遍历
.... # 循环体
当循环体中不使用自定义变量,可以将自定义变量定义为_
for _ in range(5):
print("I'm ok,thanks")
- 嵌套循环
for i in range(1, 10):
for j in range(1, i+1):
print(i, '*', j, '=', i*j)
控制语句
(需要多加练习)
- break语句
- 用于跳出当前循环(for循环或while循环),执行循环之后的代码.这是一种非正常结束循环的方式.控制本层循环.
- continue语句
- 用于跳过当前循环中剩余的代码,并开始下一次循环迭代.常与if一起使用,控制本层循环.
- pass语句
- 什么都不做,只是一个占位符,用在语法上需要语句的地方
在(先搭建语法结构,但是还没想好怎么写代码时使用)
用在if语句的条件执行体,for-in语句的循环体,定义函数的函数体
使用后不会报错
- 什么都不做,只是一个占位符,用在语法上需要语句的地方
- assert语句 在Python中,
assert
是一个断言语句,用于检查某个条件是否为真.如果条件为真,则程序继续执行;如果条件为假,则会引发AssertionError
异常,并在异常信息中显示断言失败的原因.
assert
的语法为:
assert expression, message
其中,expression
是需要验证的条件表达式,一般为布尔类型的值.message
是可选的参数,用于在断言失败时显示额外的错误信息.
下面是一些使用assert
的示例:
# 示例1:
x = 5
assert x > 0, "x必须大于0"
# 示例2:
def divide(a, b):
assert b != 0, "除数不能为0"
return a / b
# 示例3:
def check_even_number(n):
assert n % 2 == 0, "参数必须为偶数"
print("参数是偶数")
check_even_number(4) # 正常执行
check_even_number(3) # 断言失败,引发AssertionError异常
在示例1中,如果x
不大于0,则会断言失败,并在异常信息中显示"x必须大于0".由于x
的值为5,满足条件,因此断言成功,程序继续执行.
在示例2中,divide
函数将两个数相除,如果除数b
为0,则会断言失败,并在异常信息中显示"除数不能为0".由于b
的值不为0,满足条件,因此断言成功,函数正常返回.
在示例3中,check_even_number
函数用于验证一个数是否为偶数.如果参数n
不是偶数,则会断言失败,并在异常信息中显示"参数必须为偶数".由于参数n
的值为4,满足条件,因此断言成功,打印输出"参数是偶数".
断言通常用于程序开发过程中的调试和测试阶段,用于确保某个条件满足.在正式部署生产环境之前,通常会禁用或移除所有的断言语句.
数据结构
列表(list)
列表(List):列表是一种有序的,可变的数据容器,可以存储任意类型的元素.列表使用方括号 [] 表示,元素之间用逗号分隔.
变量中可以存储一个元素,而列表是一个大的容器,可以存储n多个元素,方便程序对这些数据进行整体操作.列表相当于其它语言的数组.
列表的示意图
-7 | -6 | -5 | -4 | -3 | -2 | -1 |
---|---|---|---|---|---|---|
'hello' | 'world' | 123 | 20 | 'good' | 'world' | 20 |
0 | 1 | 2 | 3 | 4 | 5 | 6 |
列表的创建
列表具有以下特点.
- 列表的元素按顺序有序排序
- 索引映射唯一一个数据
- 列表可以重复存储数据
- 列表中任意数据类型混存
- 列表根据需要动态的分配和回收内存
列表需要使用中括号[],元素之间使用英文的逗号进行分割.下面是两种方式
- 使用中括号
list1 = ['hello', 'world', 98]
- 调用内置函数list()
list2 = list(['hello', 'world', 98])
在Python中,
list()
是一种内置函数,用于将可迭代的对象(例如字符串,元组,集合或字典)转换为列表.
以下是list()
函数的用法和示例:
- 将字符串转换为列表:
string = "Hello World"
lst = list(string)
print(lst) # ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']
- 将元组转换为列表:
tuple = (1, 2, 3, 4, 5)
lst = list(tuple)
print(lst) # [1, 2, 3, 4, 5]
- 将集合转换为列表:
set = {1, 2, 3, 4, 5}
lst = list(set)
print(lst) # [1, 2, 3, 4, 5]
- 将字典的键转换为列表:
dictionary = {"name": "John", "age": 25, "city": "New York"}
lst = list(dictionary)
print(lst) # ['name', 'age', 'city']
请注意,list()
函数创建一个新的列表,并使用可迭代对象的元素填充该列表.如果使用一个字符串作为参数,则会将字符串中的每个字符作为列表的一个元素.
列表的操作
查询
- 获取列表中指定元素的索引,可以调用
index()
方法- 如果查询列表中存在n个相同元素,只返回相同元素的第一个索引
- 如果查询的元素不存在,则会抛出ValueError
- 还可以在指定的start和stop中进行查找
fruits = ['apple', 'banana', 'orange', 'banana']
index = fruits.index('banana', 2)
print(index) # 输出:3
index = fruits.index('banana', 1, 3)
print(index) # 输出:1
- 获取列表中的单个元素,采用
列表名[索引]
的形式,返回值为特定索引的元素- 正向索引从0到N-1
- 逆向索引从-1到-N
- 指定索引不存在,抛出IndexError
fruits = ['apple', 'banana', 'orange', 'banana']
print(fruits[2]) # 输出orange
- 获取列表中的多个元素,可以采用切片操作
列表名[start:stop:step]
- 切片操作
- 切片结果:源列表片段的拷贝,返回值是一个新的列表对象
- 切片范围:[start, stop)
- step默认为1,可简写为
[start:stop:]
- step为正数
- [:stop:step] 切片的第一个元素默认是列表的第一个元素往后计算切片
- [start::step] 切片的最后一个元素默认是列表的最后一个元素从start往后计算切片
- step为负数
- [:stop:step] 切片的第一个元素默认是列表的最后一个元素往前计算切片
- [start::step] 切片的最后一个元素默认是列表的第一个元素从start往前计算切片
- 判断指定元素在列表中是否存在
元素 in 列表名
元素 not in 列表名
- 列表元素的遍历
for 迭代变量 in 列表名:
操作
增删改
增加
append()
在列表的末尾添加一个元素extend()
在列表的末尾至少添加一个元素()insert()
在列表的任意位置添加一个元素- 切片 在列表的任意位置添加至少一个元素
fruits = ['apple', 'banana', 'cherry']
fruits.append('orange') # 添加元素'orange'
print(fruits) # 输出: ['apple', 'banana', 'cherry', 'orange']
fruits = ['apple', 'banana', 'cherry']
fruits.extend(['orange', 'kiwi']) # 添加可迭代对象['orange', 'kiwi']的元素
print(fruits) # 输出: ['apple', 'banana', 'cherry', 'orange', 'kiwi']
fruits = ['apple', 'banana', 'cherry']
fruits.insert(1, 'orange') # 在索引位置1插入元素'orange'
print(fruits) # 输出: ['apple', 'orange', 'banana', 'cherry']
删除
remove(元素)
(方法)- 一次删除一个元素
- 重复元素值删除第一个
- 元素不存在则抛出ValueError
pop(索引)
(方法)- 删除一个指定索引位置的元素
- 指定索引不存在则抛出IndexValue
- 不指定索引则删除列表的最后一个元素
- 切片 一次至少删除一个元素
clear
(方法) 清空列表del
删除列表
my_list = [1, 2, 3, 4, 5]
del my_list[2] # 删除索引为2的元素
print(my_list) # 输出:[1, 2, 4, 5]
my_list = [1, 2, 3, 4, 5]
my_list.remove(3) # 删除值为3的元素
print(my_list) # 输出:[1, 2, 4, 5]
my_list = [1, 2, 3, 4, 5]
removed_element = my_list.pop(2) # 删除索引为2的元素,并返回被删除的元素值
print(removed_element) # 输出:3
print(my_list) # 输出:[1, 2, 4, 5]
在上述例子中,pop()方法被用来删除索引为2的元素(值为3),并将删除的元素值赋给了变量removed_element,然后打印出删除元素后的列表和被删除的元素值.
需要注意的是,如果要删除的元素不存在于列表中,会引发ValueError异常.因此,在删除元素之前,可以使用in运算符来检查元素是否存在于列表中.例如:
my_list = [1, 2, 3, 4, 5]
if 3 in my_list:
my_list.remove(3)
print(my_list) # 输出:[1, 2, 4, 5]
else:
print("元素不存在于列表中")
上述代码中,首先使用in运算符检查元素3是否存在于列表中,如果存在则删除该元素,否则打印出提示信息"元素不存在于列表中".
修改
- 为指定索引的元素赋予一个新值
- 为指定的切片赋予一个新值
list1 = [10, 20, 30, 40]
list1[2] = 100
print(list1) # 结果为[10, 20, 100, 40]
list1[1:3:] = [300, 400, 500]
print(list1) # 结果为[10, 300, 400, 500, 40]
排序
sort()
方法,调用后不指定参数会默认将所有元素按照从小到大的顺序进行排序,可以指定参数reverse=True进行降序排序- 内置函数
sorted()
,可以指定参数reverse=True进行降序排序,原列表不发生变化,返回值是一个新的列表对象
my_list = [1, 2, 3, 4, 5]
my_list.sort()
my_list.sort(reverse=True)
print(my_list)
list_new = sorted(my_list,reverse=True)
print(list_new)
列表生成式
生成列表的公式
[i*i for i in range(1, 10)] # i*i是表示列表元素的表达式,i是自定义变量,range(1, 10)是可迭代对象(表示列表元素的表达式通常包括自定义变量)
[0 for _ in range(10)]
字典(dict)
字典(Dictionary):字典是一种键值对的数据结构,用于存储具有唯一键的元素.字典使用花括号 {} 表示,键值对之间用冒号分隔.
scores = {'张三':100, '李四':99, '王五':86}
特点:(下面的文字引用对特点进行了详细的说明)
- 字典中的所有元素都是key:value对,key不允许重复(重复会覆盖),value可以重复
- 字典中的元素是无序的
- 字典中的key必须是不可变对象(参考下面的文字说明)
- 字典可以根据需要动态地伸缩
- 字典会占用较大的内存,是一种使用空间换时间的数据结构
在Python中,字典是一种无序,可变且可迭代的数据结构,用于存储键-值对.字典中的值可以根据唯一的键进行访问和修改.在字典的实现中,Python使用了哈希函数来寻找键的位置并进行快速访问.
哈希函数是一种将输入(在这种情况下是键)映射到固定大小值的函数.该函数使用键对象的哈希值作为索引来定位键的存储位置.在Python中,哈希函数是通过
__hash__()
方法来实现的.
当你创建一个字典并添加键-值对时,Python会通过哈希函数计算每个键的哈希值,并将键值对存储在哈希表中.哈希表是一个高效的数据结构,可以根据键的哈希值快速查找和访问对应的值.当你想要访问字典中的值时,Python会使用哈希函数计算给定键的哈希值,并在哈希表中查找对应的位置,然后返回相应的值.
字典的哈希函数和哈希表的实现使得字典的查找和访问操作具有常数时间复杂度,即使字典中存储了大量的键-值对,也能保持高效的性能.(相对的占用内存也会很大)
需要注意的是,字典中的键必须是可哈希的,即键对象必须具有确定的哈希值,并且在其生命周期中保持不变.这是因为字典使用哈希函数来确定键的存储位置,如果键的哈希值在字典中的生命周期内发生变化,可能导致键无法正确定位,进而出现错误的结果.**常见的可哈希的对象包括字符串,数字类型(整数,浮点数)和元组(当只包含可哈希的对象时)**等.而列表和字典等则是不可哈希的,因为它们是可变的.
总结来说,Python中的字典使用哈希函数来实现高效的查找和访问操作.哈希函数根据键对象的哈希值将键-值对存储在哈希表中,并通过哈希函数快速定位要访问的键所在的位置.这使得字典在处理大量数据时仍能保持高效性能.
还存在哈希冲突的情况
创建
- 使用花括号
- 使用内置函数
dict()
my_dict = {}
sorces = {'张三':100, '李四':99, '王五':86} # 使用花括号创建字典
my_dict = dict([('key1', 'value1'), ('key2', 'value2'), ('key2', 'value2')]) # 使用键值对的列表创建字典
my_dict = dict([('key1', 'value1'), ('key2', 'value2'), ('key2', 'value2')]) # 使用元组的序列创建字典
my_dict = dict(key1='value1', key2='value2') # 使用关键字参数创建字典
元素的获取
字典名[key]
该操作返回的值为对应key的值get(key)
方法
[]如果字典中不存在相应的key则会抛出KeyError异常
get()方法取值,如果字典中不存在相应的key,不会抛出KeyError异常,而是返回None,可以通过指定参数设置成默认的value在指定的key不存在的时候返回sorces.get('张三', 默认值)
keys()
方法, 用于获取字典中的所有key, 返回值类型为dict_keysvalues()
方法, 用于获取字典中的所有value, 返回值类型为dict_valuesitems()
方法, 用于获取字典中的所有key:value, 返回值类型为dict_items
上述方法获得的对象均可以用
list()
函数转化,其中items()
方法获取的对象可以用list()
函数转化,转化后的列表中的元素类型为tuple
元素的判断,删除,新增,修改,遍历
- in 和 not in 用于判断key是否在字典中
del 字典名['key1']
用于删除键值对字典名.clear()
用于清空字典字典名[key] = value
用于新增和修改元素- 遍历
for item in scores: # item遍历的对象是key,scores是字典名
print(item)
print(item, scores[item], scores.get(item))
字典生成式
- 内置函数
zip()
用于将可迭代对象作为参数,将对象中相应的元素打包成一个元组,然后返回由这些元组构成的列表(在zip打包中,会优先以短的那个对象为基准进行打包,多余的元素被略去) - 字典生成式
{item.upper():float(price) for item, price in zip(items, prices) }
'''
item.upper()是表示字典key的表达式
float(price)是表示字典value的表达式
item是自定义key,price是自定义value
items和prices是可迭代对象
'''
元组(tuple)
一个不可变的有序序列
不可变序列:字符串,元组这些一经创建无法进行增删改操作的对象
可变序列:字典,列表,集合这些可以进行增删改操作的对象(对象的内存地址不发生改变)
元组储存的对象是对对象的引用(指向该对象所储存的内存地址,即id)
- 元组中的对象本身为不可变对象,则不能再引用其他对象
- 元组中的对象是可变对象,则可变对象的引用不可以改变(id不变),但可变对象内的数据可以改变
为什么要将元组设计成不可变序列?
在多任务环境下,同时操作同一个对象时不需要加锁(每个人都可以看到对象的值但无法进行修改),因此在程序中尽量使用不可变序列
操作
- 直接小括号
- 使用内置函数
tuple()
t = ('python', 'hello', 90) # 小括号可以省略
t = tuple(('python', 'hello', 90)) # 使用内置函数tuple()
t = (10,) # 只包含一个元素的元组需要使用逗号和小括号
t = () # 空元组
t = tuple()
list1 = [] # 空列表
list1 = list()
d = {} # 空字典
d = dict()
- 遍历:元组是可迭代对象,所以使用
for-in
循环可以进行遍历
元组(Tuple):元组与列表类似,但是元组是不可变的,即创建后不能修改.元组使用圆括号 () 表示,元素之间用逗号分隔. 在Python中,元组(Tuple)是一个有序,不可变的数据类型.它是由多个逗号分隔的值组成的,可以包含任何类型的数据,例如整数,浮点数,字符串等.
元组的主要特点是它们是不可变的,即一旦创建后就不能修改其内容.这意味着不能向元组中添加,删除或修改元素.不可变性使得元组在存储数据时更加安全,同时也确保了元组在多线程环境中的线程安全性.
下面是一些关于元组的重要概念:
- 创建元组:可以使用一对小括号
( )
或者tuple()
内置函数来创建一个元组.例如:
my_tuple = (1, 2, 3) # 使用括号创建元组
my_tuple = tuple([1, 2, 3]) # 使用tuple()函数创建元组
- 访问元组中的元素:元组中的元素可以通过索引来访问,索引从0开始.例如:
print(my_tuple[0]) # 输出元组中索引为0的元素
- 遍历元组:可以使用循环结构来遍历元组中的元素.例如:
for item in my_tuple:
print(item)
- 元组的切片:可以使用切片来获取元组中的一部分.切片操作返回一个新的元组,包含指定范围内的元素.例如:
my_slice = my_tuple[1:3] # 获取索引1至2之间的元素
- 元组的长度和元素个数:可以使用
len()
函数来获取元组的长度,即元素的个数.例如:
length = len(my_tuple) # 获取元组的长度
总结一下,元组是一种不可变的有序数据类型,在Python中用于存储多个元素的集合.由于其不可变性,元组比列表更适合用于存储不可更改的数据.
集合(set)
集合(Set):集合是一种无序且不重复的数据结构,可以进行常见的集合操作,如并集,交集,差集等.
- 与列表,字典一样属于可变类型的序列
- 集合是没有value的字典(同样采用了hash函数和哈希表)
创建
{}
- 使用内置函数
set()
转化(可转化的对象有列表,元组,range(),字符串,集合) - 空集合的定义(与空字典区分开)
s = {'python', 'hello', 88, 1.1} # 直接使用花括号
s = set({'python', 'hello', 88, 1.1}) # 使用内置函数set()
s = set() # 对于空集合的定义不能直接使用{},否则会和空字典混淆,要使用内置函数set()
元素的判断,新增,删除
in
和not in
add()
方法,一次添加一个元素update(集合,列表,元组)
方法,一次至少添加一个元素remove(key)
方法,一次删除一个指定元素,不存在报错KeyErrordiscard(key)
方法,一次删除一个指定元素,不存在不报错pop()
方法,一次随机删除一个元素,并返回他clear()
方法,清空集合
集合运算
- 关系
- 集合相等,用==或!=来判断
- 子集,调用
给定集合.issubset(要比较的集合)
方法来判断 - 超集,调用
给定集合.issuperset(要比较的集合)
方法来判断 - 交集,调用
给定集合.isdisjoint(要比较的集合)
方法来判断(有则返回False,无则返回True)
- 运算
- 并集,调用方法
s1.union(s2)
或者s1 | s2
获得 - 交集,调用方法
s1.intersection(s2)
或者s1 & s2
获得 - 差集,调用方法
s1.difference(s2)
或者s1 - s2
获得 - 对称差集,调用方法
s1.symmetric_difference(s2)
或者s1 ^ s2
获得
- 并集,调用方法
集合生成式
{i**6 for i in range(1, 10)}
'''
i**6表示集合元素的表达式
i是自定义变量(和集合元素表达式有关系)
range(1, 10)是可迭代对象
将{}改成[]就是列表生成式
'''
在Python中,set(集合)是一种无序,可变且没有重复元素的数据类型.它是由一组唯一的元素组成,用大括号 {} 来表示,每个元素之间使用逗号分隔.
以下是set数据类型的一些特点和相关操作:
- 元素的唯一性:set中的元素是不可重复的,如果多次添加相同的元素,只会保留一份.
- 无序性:set中的元素没有特定的顺序,不能通过索引访问.这是因为set内部使用哈希表来存储元素,所以元素的存储顺序是不确定的.
- 可变性:set是可变的,可以添加,删除和修改元素.
下面是一些示例,演示了set的常见操作:
- 创建set:
fruits = {"apple", "banana", "orange"}
print(fruits) # 输出: {'orange', 'banana', 'apple'}
- 添加元素:
fruits.add("grape")
print(fruits) # 输出: {'orange', 'banana', 'apple', 'grape'}
- 删除元素:
fruits.remove("banana")
print(fruits) # 输出: {'orange', 'apple', 'grape'}
- 检查元素是否存在:
print("apple" in fruits) # 输出: True
print("mango" in fruits) # 输出: False
- 遍历set:
for fruit in fruits:
print(fruit)
- 数学上的集合操作:
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
# 并集
print(set1.union(set2)) # 输出: {1, 2, 3, 4, 5, 6, 7, 8}
# 交集
print(set1.intersection(set2)) # 输出: {4, 5}
# 差集
print(set1.difference(set2)) # 输出: {1, 2, 3}
# 对称差集(两个集合的元素除了共有的部分,其它的元素都包含在该集合中)
print(set1.symmetric_difference(set2)) # 输出: {1, 2, 3, 6, 7, 8}
总结:set类型在处理需要唯一元素且不关心元素顺序的情况下非常有用.它提供了一组方便的操作来处理集合,如添加,删除,判断成员关系等.
函数
定义和调用函数
函数就是执行特定任务以完成特定功能的一段代码
使用函数的原因
- 复用代码
- 隐藏实现细节
- 提高可维护性
- 提高可读性便于调试
函数的创建
def 函数名(参数1, 参数2, ...):
函数体
(return xxx) # 可以不返回值
'''
类比榨汁机,不需要知道它工作的细节,只需要知道它能榨汁,参数相当于放入的水果,return返回的是榨好的果汁
'''
def sum_two(a, b):
c = a + b
return c
# 第一步,跳入定义的函数体内
# 第二步,执行函数体
# 第三步,跳到函数的调用处
# 第四步,继续执行下一步语句
result = sum_two(10, 20)
print(result)
参数和返回值
函数的参数传递
- 位置实参
- 根据形参对应的位置进行实参传递
- 关键字实参
- 根据形参名称进行实参传递
- 两者可以同时使用
例如:
def calc(a, b): # a,b占用了两个变量位置,称为形式参数,出现在函数的定义中
c = a + b
return c
# 位置实参
s = calc(10, 20) # 10, 20都是实际参数,是在函数调用中输入给函数的
# 关键字实参
s = calc(b=10, a=20)
函数调用的参数传递内存分析(图表)
形式参数和实际参数的名称可以不相同
在函数调用过程中,进行参数的传递
def fun(arg1, arg2):
print(arg1)
print(arg2)
arg1 = 100
arg2.append(10)
print(arg1)
print(arg2)
n1 = 11
n2 = [22, 33, 44]
print(n1)
print(n2)
fun(n1, n2)
print(n1)
print(n2)
'''在这个示例中,fun()函数调用时,n1是不可变对象,其值本身没有改变,n2是可变对象,其值发生了改变,末尾被追加了一个元素'''
如果是不可变对象,在函数体内的修改不会影响实际参数的值
如果是可变对象,在函数体内的修改会影响实际参数的值
函数的返回值
- 函数返回多个值时,结果为元组
- 函数没有返回值(函数执行完毕之后,不需要给调用处提供数据),return可以省略不写
- 函数的返回值如果是一个元素,直接返回原值,类型不改变
def fun(num):
odd = []
even = []
for i in num:
if i%2:
odd.append(i)
else:
even.append(i)
return odd, even
list1 = [10, 29, 36, 55, 113]
print(fun(list1)) # ([29, 55, 113], [10, 36]),函数返回多个值时,结果为元组
在Python中,函数是一段可重用的代码块,用于执行特定任务.函数的定义包括函数名,参数列表和函数体.定义函数的语法如下:
def function_name(parameter1, parameter2, ...):
# 函数体
# 可执行的代码
# 可以包含多行语句
return result
- 函数名:是标识函数的名称,应该以字母或下划线开头,可以包含字母,数字和下划线.函数名应该具有描述性,以便让其他开发人员更容易理解代码.
- 参数列表:函数可以接受零个或多个参数,参数是函数调用时传递给函数的值.当定义函数时,我们在参数列表中列出参数的名称.如果函数不需要参数,可以使用空的括号表示函数没有参数.
- 函数体:是一个由缩进的代码块,它定义了函数的操作.函数体中的代码实现了函数所需的逻辑和计算过程.可以使用
return
语句返回函数的结果.如果函数没有定义return
语句,则函数将返回None
值.
函数定义后,可以通过调用函数来执行其中的代码.要调用函数,只需使用函数名,并传递相应的参数.例如:
result = function_name(argument1, argument2, ...)
在调用函数时,需要注意以下事项:
- 函数名后面的圆括号是必需的,即使没>有参数也不能省略.
- 调用函数时,需要传递与参数列表中定义的参数数量和顺序相匹配的参数.
- 函数可以返回一个值,可以将返回值存储在变量中或直接使用.
函数的参数定义
参数:
- 关键字参数(以键值对的形式传递的参数)
- 位置参数(以单个值的形式传递的参数)
*
将序列中的每一个元素转换为位置实参**
将序列中的每一个元素转换为关键字实参
def fun(a, b, c):
print(a)
print(b)
print(c)
list1 = [10, 30, 20]
fun(*list1) # 将列表中每一个元素转化为位置实参
dic = {'a':111, 'b':222, 'c':333}
fun(**dict) # 将字典中每一个元素转化为关键字实参
- 函数定义默认值参数
- 函数定义时,给形参设置默认值,只有与默认值不符的时候才需要传递实参
def fun(a, b=10): # b称为默认值参数
print(a, b)
# 函数的调用
fun(100) # 只传递一个参数,b采用默认值
fun(20,30) # 传递两个参数,且第二个与b对应的参数与默认值不相同,则30将替换10
- 个数可变的位置参数(只能定义一个)
- 定义函数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置形参
- 使用
*
定义个数可变的位置形参 - 结果为一个元组
- 个数可变的关键字形参(只能定义一个)
- 定义函数时,可能无法事先确定传递的关键字实参的个数时,使用可变的关键字形参
- 使用
**
定义个数可变的关键字形参 - 结果为一个字典
- 在一个函数的定义过程中,既有个数可变的关键字形参,又有个数可变的位置形参,要求个数可变的关键字形参放在个数可变的位置形参之后
# 个数可变的位置参数
def fun(*args):
print(args)
fun(10)
fun(10, 20)
fun(10, 20, 30)
# 个数可变的关键字参数
def fun(**args):
print(args)
fun(a=10)
fun(a=10, b=20, c=100)
# 特殊用法
def fun(a,b,*,c,d): # 在*之后的参数采用关键字参数传递
在Python中,函数的个数可变的关键字形参(variable-length keyword parameters)和个数可变的位置形参(variable-length positional parameters)允许我们在定义函数时不提前指定参数的个数,从而使函数能够接受任意数量的参数.
- 个数可变的关键字形参:
- 当我们希望函数能够接受任意数量的关键字参数(以键值对的形式传递的参数),我们可以使用个数可变的关键字形参.
- 在函数定义中,使用一个以星号(*)开头的形参来表示个数可变的关键字形参.通常,这个形参被命名为
**kwargs
(也可以选择其他名称).- 在函数体内,
kwargs
实际上是一个字典,其中包含了传递给函数的关键字参数.我们可以使用字典相关的操作(例如索引,遍历等)来处理这个参数.- 下面是一个接受个数可变关键字形参的函数的示例:
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
# 调用函数,传递关键字参数
print_info(name="Alice", age=25, city="New York")
# 输出:
# name: Alice
# age: 25
# city: New York
- 个数可变的位置形参:
- 当我们希望函数能够接受任意数量的位置参数(以单个值的形式传递的参数),我们可以使用个数可变的位置形参.
- 在函数定义中,使用一个以星号(*)开头的形参来表示个数可变的位置形参.通常,这个形参被命名为
*args
(也可以选择其他名称).- 在函数体内,
args
实际上是一个元组,其中包含了传递给函数的位置参数.我们可以使用元组相关的操作(例如索引,遍历等)来处理这个参数.- 下面是一个接受个数可变位置形参的函数的示例:
def print_items(*args):
for item in args:
print(item)
# 调用函数,传递位置参数
print_items("apple", "banana", "orange")
# 输出:
# apple
# banana
# orange
个数可变的关键字形参和个数可变的位置形参可以同时在同一个函数中使用(有先后顺序).使用它们可以增加函数的灵活性,并允许我们编写接受不同数量参数的函数.
变量的作用域
- 程序代码能访问该变量的区域
- 根据变量的有效范围可分为
- 局部变量
- 在函数定义并使用的变量,之在函数内部有效,局部变量使用global声明,这个变量就会变成全局变量
- 全局变量
- 函数体外的变量,可作用于函数内外
- 局部变量
def fun(a, b):
c= a + b
print(c)
'''
c是在函数体内定义的变量,a,b是函数的形式参数,作用范围都是函数内部,是局部变量
print(a) # 程序将报错
print(c) # 程序依然报错
这两个变量只在函数内部有效,a,c在这里调用超出了它的作用域
'''
name = 'aa'
print(name)
def fun():
print(name)
print(name)
'''这里的name是全局变量,无论是函数内外都可以使用,作用范围为全局'''
def fun1():
global age # 对age进行全局变量声明
age = 20
print(age)
fun1()
print(age)
递归函数
- 递归函数:如果一个函数的函数体调用了该函数本身,这个函数就称为递归函数
- 递归的组成部分:递归调用与递归终止条件
- 递归的调用过程
- 每递归调用一次函数,都会在栈内存分配一个栈帧
- 每执行完一次函数,都会释放相应的空间
- 递归的优缺点
- 缺点:占用内存多,效率低下
- 优点:代码和思路简单
这句话是在描述Python中递归函数的工作原理和内存管理.让我们逐步解释其含义和涉及的知识点:
递归函数:递归是指函数在其定义中调用自身的过程.在递归函数中,函数会反复调用自身,以解决更小规模的子问题,直到达到基本情况或条件,从而结束递归.
栈帧:栈帧是在执行函数时创建的一种数据结构,用于存储函数的局部变量,返回地址和其他与函数调用相关的信息.每次调用函数时,都会在内存中分配一个新的栈帧.
内存分配:当递归函数被调用时,计算机会为每个函数调用创建一个新的栈帧,并将其推入执行栈(call stack)中.栈帧中存储了函数的局部变量和其他相关信息.这样,每一层递归函数都会有自己的栈帧,并按照调用顺序依次排列在执行栈中.
空间释放:当递归函数的执行达到基本情况或条件时,函数将不再调用自身,递归过程开始回溯.在回溯的过程中,每次函数完成执行,它的栈帧会从执行栈中弹出,这意味着它占用的内存空间被释放.
因此,递归函数每次调用时,在内存中分配一个新的栈帧以保存局部变量和其他相关信息.而每次函数完成执行并返回时,其栈帧会被释放,回收相应的内存空间.这种栈帧的分配和释放过程允许递归函数正常工作,并避免了内存泄漏问题.
递归函数是一种在函数内部调用自己的函数.当调用递归函数时,函数会重复执行自己,直到满足某个条件才停止递归调用.
下面是递归函数的工作原理的详细说明:
函数定义:定义一个函数,并在函数内部包含对自身的调用.例如,一个计算阶乘的递归函数可以这样定义:
pythondef factorial(n): if n == 0: return 1 else: return n * factorial(n-1)
基本情况(停止条件):在递归函数中,必须定义一个或多个停止递归的条件,即基本情况.这些基本情况通常是输入值满足某个条件时,函数不再继续递归调用,而是返回一个特定的值.
在上述示例中,如果
n
的值为0,则递归调用停止,函数直接返回1,这是阶乘的边界情况.递归调用:在递归函数的定义中,函数会以较小的输入值进行自我调用.这意味着在每次递归调用中,问题的规模都会减小.
在上述示例中,
factorial(n-1)
是函数自身的递归调用.通过将问题的规模从n
减小到n-1
,函数可以反复调用自身,直到达到基本情况.递归结束条件:递归函数必须包含一个结束条件,以避免无限递归调用.如果没有适当的结束条件,递归函数将一直调用自身,导致程序崩溃.
在上述示例中,当
n
的值为0时,阶乘的计算结束,函数直接返回结果1,这是递归函数的结束条件.递归函数的执行流程:当调用递归函数时,函数首先检查基本情况.如果基本情况满足,函数返回一个值并结束递归.否则,函数会进行递归调用,将问题的规模减小一步,并将递归调用的结果与其他操作结合.
在上述示例中,每次递归调用时,函数计算
n
和factorial(n-1)
的乘积,并返回结果.这些结果逐级返回给较大的问题,直到函数达到基本情况.
总之,递归函数通过在函数内部不断调用自身来解决较大问题,其中包括基本情况和递归调用.递归函数的一个重要方面是确保定义适当的结束条件,以避免无限递归调用.
Lambda表达式
BIF
输出函数print()
print()
是一个用于在控制台上输出文本信息的内置函数,它可以接受一个或多个参数,并将它们打印到控制台或文件中,以供用户查看.
print(value1,value2,...,sep='',end='',file=sys.stdout,flush=False)
参数说明
value1, value2, ...
:要打印的一个或多个值.可以是数字,字符串,变量或表达式.(对于表达式输出的是其计算的结果)sep
(可选):用于分隔多个值之间的字符串,默认为一个空格.end
(可选):打印结束后要追加的字符串,默认为换行符\n
.file
(可选):指定输出的文件对象,默认为标准输出(控制台).(可以输出在文件中,下面是示例)
fp=open('路径',a+)
print('hello world',file=fp)
flush
(可选):控制是否刷新输出缓冲区,默认为 False.如果设置为 True,则将立即将内容刷新到文件或控制台.
转义字符
- 当字符串中包含反斜杠,单引号和双引号等有特殊用途的字符时,必须使用反斜杠对这些字符进行转义,否则会报错(可以交替使用单双引号规避该问题)
print("I'm superman")
- 当字符串中包含换行回车水平制表符或退格等无法直接表示的特殊字符时,也可以使用转义字符
- 原字符:不希望字符串中的转义字符起作用,就可以使用原字符,即在字符串之前加上r或者R
print(r'hello world \n good')
- 字符串的最后一个字符不能是反斜杠(但可以用另一个反斜杠给该反斜杠做转义)
输入函数input()
用于接收用户的输入
返回值的类型是str
值的储存要使用变量赋值的方法对输出的值进行储存
可以指定提示词(会打印在屏幕上)
a = input('请输入你的名字')
range()函数
用于生成一个整数序列,返回值是一个迭代器对象
r = range(10)
print(r) # 结果为range(0, 10)
print(list(r)) # 结果为[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],这里的list()把迭代器对象转化为了列表
创建range对象的三种方式
- range(stop) 创建一个[0,stop)的整数序列,步长为1
- range(start, stop) 创建一个[start,stop)的整数序列,步长为1
- range(start, stop, step) 创建一个[start,stop)的整数序列,步长为step
优点:不管range对象表示的整数序列有多长,所有的range对象所占用的内存空间都是相同的,因此只需要储存start,stop,step,只有当用到range对象时才会计算序列中的相关元素
in和not in可用来判断整数序列中是否存在或不存在指定的整数
isinstance()函数
在Python中,isinstance()
函数用于检查某个对象是否是指定类型的实例.它的语法如下:
isinstance(object, classinfo)
object
:要检查的对象.classinfo
:可以是类名,类型或由类名组成的元组.
isinstance()
函数的返回值为布尔类型,如果对象是指定类型的实例,则返回True
;否则返回False
.
以下是一些使用示例:
# 检查整数类型
num = 10
print(isinstance(num, int)) # True
# 检查字符串类型
name = "John"
print(isinstance(name, str)) # True
# 检查列表类型
my_list = [1, 2, 3]
print(isinstance(my_list, list)) # True
# 检查多个类型
my_tuple = (1, 2, 3)
print(isinstance(my_tuple, (list, tuple))) # True(因为my_tuple是元组类型)
# 检查自定义类的实例
class MyClass:
pass
obj = MyClass()
print(isinstance(obj, MyClass)) # True
isinstance()
函数在编写多态代码时很有用,可以判断对象是否属于某个类或其子类.
类
类和对象的创建
类:多个类似事物组成群体的统称.能够帮助我们快速理解和判断事物的性质(分门别类)
人类,动物类,鸟类......
- 数据类型
- 不同的数据类型属于不同的类
- 使用内置函数查看数据类型
print(type(100)) # <class 'int'>
print(type(99)) # <class 'int'>
print(type(520)) # <class 'int'>
- 对象
- 100,99,520都是int类型之下包含的相似的不同的个例,这些个例专业术语称为实例或对象
python中一切皆对象,对象应该有类型,id,和值
- 100,99,520都是int类型之下包含的相似的不同的个例,这些个例专业术语称为实例或对象
- 字符串对象
- 列表对象
- 元组对象
- 整数对象
- 字典对象
- .......
类的创建
类的组成
- 类属性
- 实例方法
- 静态方法
- 类方法
创建类的语法
class Student: # Student为类的名称(类名),由一个或多个单词组成,每个单词的首字母大写,其余小写(规范)
pass
print(id(Student),type(Student),Student)
'''
1675292138448
<class 'type'>
<class '__main__.Student'>
'''
class Student:
# 类属性
native_place = '吉林' # 直接写在类里的变量,称为类属性
# 实例方法
def eat(self): # 实例方法(在类之内定义的称为实例方法,在类之外定义的称为函数)# ,默认参数为self
print('学生在吃饭...')
# 静态方法
@staticmethod
def method(): # 没有默认参数
print('我使用了staticmethod进行修饰,所以我是静态方法')
# 类方法
@classmethod
def cm(cls): # 默认参数为cls
print('我使用了classmethod进行修饰,所以我是类方法')
# __init__初始化方法
def __init__(self, name, age):
self.name = name
'''
self.name称为实例属性,进行了一个赋值的操作,将局部变量name的值赋给实例属性
局部变量和实例属性的名称不必须相同,但是习惯上是要相同的
'''
self.age = age
self对应的是对于实例本身的引用 以self为前缀的变量可供类中的所有方法使用
对象的创建
- 对象的创建又称为类的实例化
- 意义:有了实例就可以调用类中的内容
- 语法:
# 创建Student类的实例对象
stu = Student()
print(stu.name) # 实例属性
print(stu.age) # 实例属性
stu.info() # 实例方法
# 实例名 = 类名()
stu1 = Student('张三', 20)
print(id(stu1))
print(type(stu1))
print(stu1)
'''
2630442394576
<class '__main__.Student'>
<__main__.Student object at 0x000002647295A3D0>
输出对象的时候,输出了该对象的内存地址2630442394576的16进制数0x000002647295A3D0
'''
Student.eat(stu1)
stu1.eat()
'''
使用实例方法,两种方法都可
第一种方法把对象作为变量传给实例方法
>>>>对象名.方法名()
第二种方法中实例方法的定义中的self,调用时会将对象自身传给方法
>>>>类名.方法名(类的对象)
'''
print(stu1.name)
print(stu1.age)
类属性,类方法,静态方法
- 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享
- 类方法:使用@classmethod修饰的方法,使用类名直接访问的方法
- 静态方法:使用@staticmethod修饰的方法,使用类名直接访问的方法
print(stu1.native_place)
print(Student.native_place) # 访问类属性
Student.native_place = '...' # 类属性的修改
Student.cm() # 调用类方法
Student.sm() # 调用静态方法
# 类方法的使用方式
Student.cm()
动态绑定属性和方法
- Python是动态语言,在创建对象之后,可以动态地绑定属性和方法
class Student:
def __init__(self, name, age): # 初始化方法
self.name = name # 实例变量
self.age = age
def eat(self):
print(self.name + '在吃饭')
stu1 = Student('张三', 20)
stu2 = Student('李四', 30)
def show():
print('我是函数')
'''在类外'''
stu = Student('Jack', 20)
stu.gender = '男' # 动态绑定属性(只对当前变量绑定,不对所有变量绑定)
print(stu.name, stu.age, stu.gender)
stu.show = show # 动态绑定方法(只对当前变量绑定,不对所有变量绑定)
stu.show()
类的浅拷贝和深拷贝
- 变量的赋值操作
- 只是形成两个变量,实际上还是指向同一个对象
- 浅拷贝
- Python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象 -相当于创建快捷方式 (包含的只是引用)-
import copy
# 需要导入copy模块
- 深拷贝
- 使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
在Python中,浅拷贝(shallow copy)和深拷贝(deep copy)是用于创建对象副本的两个概念. 浅拷贝是创建一个新对象,并将原始对象的元素的引用复制到新对象中.换句话说,浅拷贝创建了一个新的引用,指向与原始对象相同的数据.当原始对象是可变对象时,对新对象的修改也会反映在原始对象中. 深拷贝是创建一个新对象,并将原始对象的所有元素递归地复制到新对象中.深拷贝不仅复制原始对象的元素,还会复制其内部包含的所有对象.这意味着修改新对象不会影响原始对象,因为它们具有不同的内存地址. 为了实现浅拷贝和深拷贝,Python提供了一些方法:
- 浅拷贝:
- 使用切片操作符
[:]
进行浅拷贝,例如:new_list = old_list[:]
- 使用内置的
copy()
函数进行浅拷贝,例如:new_list = copy.copy(old_list)
- 使用
list()
,dict()
,set()
等构造函数也可以进行浅拷贝.
- 深拷贝:
- 使用
copy.deepcopy()
函数进行深拷贝,例如:new_list = copy.deepcopy(old_list)
- 使用
pickle
模块的copy()
函数进行深拷贝,例如:new_list = pickle.copy(old_list)
需要注意的是,深拷贝可能会涉及递归和更多的内存开销,因此在处理大型对象或嵌套对象时要谨慎使用.
有关问题的释疑
1 类属性
A:请详细解释Python中类的类属性
Q:在Python中,类是一种用户自定义的数据类型,可以包含属性和方法.类属性是定义在类中的共享属性,类的所有实例对象都可以访问并共享这些属性.下面是对类属性的详细解释:
- 类属性的定义:类属性定义在类的内部,但在任何方法之外.它们使用类名来访问,也可以通过类的实例进行访问.可以在类的任何位置对类属性进行赋值.例如:
class MyClass:
class_attribute = "Hello"
# 访问类属性
print(MyClass.class_attribute) # 输出: Hello
# 通过类的实例访问类属性
obj = MyClass()
print(obj.class_attribute) # 输出: Hello
- 类属性的共享:类属性是类的所有实例对象共享的,即它们在内存中只有一份拷贝.如果对类属性进行修改,所有实例对象都能看到修改后的值.例如:
class MyClass:
class_attribute = "Hello"
obj1 = MyClass()
obj2 = MyClass()
# 修改类属性的值
MyClass.class_attribute = "World"
# 所有实例对象都能访问到修改后的值
print(obj1.class_attribute) # 输出: World
print(obj2.class_attribute) # 输出: World
- 类属性的访问方式:类属性可以通过类名直接访问,也可以通过实例对象进行访问.如果实例对象和类都有同名属性,则实例对象访问的是实例属性,而不是类属性.例如:
class MyClass:
class_attribute = "Hello"
def __init__(self):
self.instance_attribute = "World"
obj = MyClass()
# 访问类属性
print(MyClass.class_attribute) # 输出: Hello
# 通过实例对象访问类属性
print(obj.class_attribute) # 输出: Hello
# 实例属性优先于类属性
print(obj.instance_attribute) # 输出: World
- 类属性的修改:类属性可以在任何地方进行修改.可以通过类名或实例对象进行修改.如果通过实例对象修改类属性,实际上是创建了一个与类属性同名的实例属性,将会屏蔽类属性.例如:
class MyClass:
class_attribute = "Hello"
obj = MyClass()
# 通过类名修改类属性的值
MyClass.class_attribute = "World"
# 通过实例对象修改类属性的值(实际上是创建了一个实例属性)
obj.class_attribute = "OpenAI"
print(MyClass.class_attribute) # 输出: World
print(obj.class_attribute) # 输出: OpenAI
总之,类属性是定义在类中的共享属性,可以通过类名或实例对象进行访问和修改.它们在类的所有实例对象之间共享,并且可以作为类在不同实例对象之间传递信息的一种方式.
2 类方法
A:请详细解释Python中类的类方法
Q:在Python中,类方法是定义在类中的一种特殊方法.类方法使用@classmethod
装饰器进行声明,并且第一个参数通常命名为cls
,表示类本身.
类方法可以通过类本身被调用,而不是通过类的实例来调用.这使得类方法能够访问类级别的属性和方法,而不依赖于实例的状态.类方法通常用于执行与类相关的操作,如在创建类的实例之前进行一些预处理或提供与类相关的实用功能.
下面是一个示例,演示如何定义和使用类方法:
class MyClass:
class_variable = 10
@classmethod
def class_method(cls, x):
print("Class variable:", cls.class_variable)
print("Input value:", x)
# 调用类方法
MyClass.class_method(5)
输出:
Class variable: 10
Input value: 5
在上面的示例中,我们定义了一个名为class_method
的类方法.它打印了类变量class_variable
的值以及传递给方法的参数.请注意,我们直接通过类名调用了类方法,而不是通过创建类的实例来调用.
类方法经常与类变量搭配使用,因为它们可以直接访问类级别的数据.但是需要注意的是,类方法不能访问实例级别的属性,因为它们不依赖于实例的存在.
总结一下,类方法在Python中是一种特殊的方法,使用@classmethod
装饰器进行声明.它们被用于执行与类相关的操作,并且可以直接通过类名调用.通过类方法,我们可以访问类级别的属性和方法,而不依赖于实例的状态.
3 类指针
A:请详细解释Python中类的类指针
Q:在Python中,类是一种特殊的对象,它具有在其定义中声明的属性和方法.类指针是一个指向类对象的引用,它允许我们访问和操作类的属性和方法.
要理解类指针,首先需要了解对象.在Python中,每个对象都有一个类型,该类型决定了对象可以具有的属性和可以调用的方法.当我们创建一个类并实例化它时,我们实际上创建了一个对象.
类指针是用于引用类对象的变量.通过该指针,我们可以访问类的属性和方法,并在需要的时候创建对象.我们可以将类指针看作是类的代表,因为它允许我们操作类.
以下是一个简单的示例来说明类指针的用法:
class MyClass:
def __init__(self, value):
self.value = value
def my_method(self):
print("Hello, World!")
# 创建类指针
my_class_ptr = MyClass
# 使用类指针创建对象并调用方法
my_object = my_class_ptr(10)
my_object.my_method()
在上面的示例中,my_class_ptr
是指向 MyClass 类的指针.我们可以使用该指针创建对象 my_object
,并调用类方法 my_method()
.
总结一下,类指针是一个引用,指向类对象.它允许我们访问类的属性和方法,并在需要时创建对象.类指针允许我们在运行时对类进行操作和扩展,使得面向对象编程更加灵活和强大.
4 实例方法
A:请详细解释Python中类的实例方法
Q:在Python中,类是一种对象的蓝图,用于定义对象的属性和方法.一个类可以创建多个实例,并且每个实例都可以具有相同的属性,但是可能具有不同的属性值.实例方法是类中的一种方法,它可以在类的实例上调用,并且可以访问实例的属性和其他实例方法.
实例方法是在类中定义的普通函数,但是它们必须包含一个额外的参数self
,该参数指向调用该方法的实例.这个self
参数用于引用实例本身.
下面是一个示例,演示如何在Python中定义和使用类的实例方法:
class MyClass:
def __init__(self, name):
self.name = name
def say_hello(self):
print("Hello, my name is", self.name)
def change_name(self, new_name):
self.name = new_name
# 创建一个实例
obj = MyClass("John")
# 调用实例方法
obj.say_hello() # 输出:Hello, my name is John
# 调用另一个实例方法
obj.change_name("Alice")
obj.say_hello() # 输出:Hello, my name is Alice
在上面的示例中,我们定义了一个名为MyClass
的类,它有一个构造方法__init__
和两个实例方法say_hello
和change_name
.
__init__
方法是特殊的方法,用于在创建类的实例时进行初始化.在这里,我们将参数name
赋值给实例的属性self.name
.say_hello
方法是一个简单的实例方法,用于打印出实例的名称.change_name
方法是另一个实例方法,可以用于更改实例的名称.
我们通过实例化MyClass
类创建了一个名为obj
的实例,并调用了say_hello
方法来打印初始的名称.然后,我们调用了change_name
方法来更改实例的名称,并使用say_hello
方法再次打印新的名称.
总结起来,实例方法允许类的实例去操作和访问它们自己的属性,并且可以根据需要执行特定的操作.实例方法是面向对象编程中的一个重要概念,使得类的实例能够封装数据和行为.
5 静态方法
A:请详细解释Python中类的静态方法
Q:在Python中,类的静态方法是一种与类相关的方法,它可以在不需要创建类实例的情况下调用.静态方法与实例方法和类方法不同,它不会操作类或实例的属性或方法,而是提供与类相关但不依赖于类的功能.
要定义一个静态方法,你可以使用@staticmethod
装饰器并将其放在方法的上方.静态方法没有对类或实例的引用作为默认参数,因此它们不会自动获得任何与类相关的信息.
以下是一个例子来演示如何定义和使用静态方法:
class MyClass:
@staticmethod
def my_static_method(arg1, arg2):
# 静态方法的实现
return arg1 + arg2
# 调用静态方法
result = MyClass.my_static_method(1, 2)
print(result) # 输出: 3
在上面的例子中,我们定义了一个名为my_static_method
的静态方法.它接受两个参数并返回它们的和.注意,调用静态方法时,我们直接使用类名称而不是类实例来调用该方法.
静态方法可以在类定义之外的地方使用.你可以在相同的类中或其他地方通过类名称调用静态方法,而不需要创建类的实例.
尽管静态方法在某些情况下很有用,但是请记住,它们没有对实例或类属性的访问权限,因此它们仅限于执行与类相关但不需要访问实例或类状态的操作.
6 init
A:请详细解释Python中类的__init__方法
Q:在Python中,类的__init__
方法是一个特殊的方法,用于在创建类的实例时进行初始化操作.它是类中的一个构造函数,当类的实例被创建时,__init__
方法会自动被调用.
__init__
方法的定义通常如下:
class MyClass:
def __init__(self, arg1, arg2):
self.attribute1 = arg1
self.attribute2 = arg2
在这个例子中,__init__
方法接受两个参数arg1
和arg2
.self
参数是一个特殊的参数,用于表示类的实例本身.在__init__
方法中,我们可以通过self
来访问和操作实例的属性.
一旦类的实例被创建,__init__
方法会自动被调用,并且传入相应的参数.在方法体中,我们可以通过self.attribute
的方式来设置实例的属性.在上述例子中,arg1
和arg2
的值被分别赋给了self.attribute1
和self.attribute2
.
下面是一个使用__init__
方法的示例:
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
car1 = Car("Toyota", "Camry", 2021)
print(car1.make) # 输出:Toyota
print(car1.model) # 输出:Camry
print(car1.year) # 输出:2021
在这个例子中,我们创建了一个Car
类,它具有make
,model
和year
三个属性.当创建car1
实例时,我们传入相应的参数,并通过self.make
,self.model
和self.year
来存储这些属性值.最后,我们可以通过实例来访问这些属性.
总之,__init__
方法是类中用于初始化实例的特殊方法,它在实例创建时自动调用,并可以用来接收参数并设置实例的属性.
7 实例变量
在Python中,实例变量指的是属于类实例的变量,每个对象都可以有自己的实例变量.实例变量是在类内部定义的普通变量,通常在类的构造方法(__init__方法)中初始化.
下面是一个简单的示例,其中定义了一个名为Person的类,它包含一个实例变量name:
class Person:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, my name is {self.name}.")
# 创建两个Person对象,每个对象都有自己的实例变量name
p1 = Person("Alice")
p2 = Person("Bob")
# 调用实例方法greet,并访问实例变量name
p1.greet() # 输出: Hello, my name is Alice.
p2.greet() # 输出: Hello, my name is Bob.
在上述示例中,每个Person对象都有一个独立的name实例变量,可以通过self.name访问和修改.每个对象的name变量被初始化为不同的值,因此在调用实例方法greet时,输出的结果也不同.这展示了实例变量如何为每个对象提供了自己的状态和数据.
面向对象编程
两大编程思想
- 面向过程
- 事物比较简单,可以用线性的思维去解决
- 面向对象
- 事物比较复杂,使用简单的线性思维无法解决 共同点:二者相辅相成,并不是对立的,都是解决实际问题的一种思维方式
解决复杂问题,通过面向对象方式便于我们从宏观把握事物之间的复杂关系,方便我们分析整个系统
具体到微观操作,仍然使用面向过程的方式处理
- 事物比较复杂,使用简单的线性思维无法解决 共同点:二者相辅相成,并不是对立的,都是解决实际问题的一种思维方式
编程思想是指在解决问题和开发软件过程中所采用的方法和思维方式.它是指导程序设计的原则和理念,帮助开发人员更好地规划,设计和构建软件系统.
以下是一些常见的编程思想:
- 结构化编程思想:结构化编程强调使用顺序,选择和循环等基本控制结构,以组织,控制程序的执行流程.
- 面向对象编程思想:面向对象编程(OOP)将程序看作是由对象组成的,强调将问题划分为一组相互关联的对象,通过对象之间的交互来解决问题.
- 函数式编程思想:函数式编程(FP)将计算看作是数学函数的求值过程,强调使用纯函数和避免可变状态,以实现可靠,可复用和可维护的代码.
- 响应式编程思想:响应式编程(RP)关注数据流和事件之间的关系,通过定义数据流和响应式操作来处理数据的变化,使系统能够高效地处理异步事件.
- 并发编程思想:并发编程涉及处理程序的同时执行多个任务的能力,强调使用线程,进程或异步编程来提高程序的效率和响应性.
- 领域驱动设计思想:领域驱动设计(DDD)关注理解和模型化问题所涉及的业务领域,通过将业务逻辑映射到软件设计中,实现更高效,可维护和可扩展的系统.
这些编程思想并非相互排斥,通常可以根据具体的问题和需求选择合适的思想或将它们结合起来使用.
面向对象的三大特征(通用)
- 封装:用于提升程序的安全性
- 将数据(属性)和行为(方法)包装到类对象中.在方法内部对属性进行操作,在类对象的外部调用方法.这样,无需关心方法内部的具体实现细节,从而隔离了复杂度.
- 在python中没有专门的修饰符用于属性的私有,如果不希望属性在类对象的外部被访问,前面使用两个'_'
- 继承:提高代码的复用性
- 多态:提高程序的可扩展性和可维护性
封装
class Student:
def __init__(self, brand)
self.brand = brand
def start(self):
print('汽车已启动......')
car = Car('宝马X5')
car.start()
print(car.brand) # 封装
class Student:
def __init__(self, name, age):
self.name = name
self.__age = age # age不希望在类的外部被使用,所以加了两个_(但是可以在类的内部使用)
def show(self):
print(self.name, self.__age)
stu = Student('张三', 20)
stu.show
print(stu.name)
print(stu.__age) # 不希望在外部使用
print(dir(stu)) # 获取....
# 在类的外部通过_Student__age进行访问(靠自觉)
继承
类似于不同层次的区分(具有包含关系)
动物是爬行动物和哺乳动物的父类
爬行动物是蛇和鳄鱼的父类
- 语法格式
class 子类类名(父类1, 父类2, ...):
pass
- 如果一个类没有继承任何类,则默认继承object
- Python支持多继承
- 定义子类时,必须在其构造函数中调用父类的构造函数
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print('姓名:{0},年龄:{1}'.format(self.name, self.age))
# 定义子类
class Student(Person):
def __init__(self, name, age, score):
super().__init__(name, age) # 用super()调用父类
self.score = score
# 测试
stu = Student('Jack', 20, '1001')
stu.info()
方法重写
- 方法重写
- 如果子类对继承于父类的某个属性或方法不满意,可以在子类中对其(方法体)进行重新编写
- 子类重写后的方法可以通过super().xxx()调用父类中被重写的方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print('姓名:{0},年龄:{1}'.fomat(self.name, self.age))
# 定义子类
class Student(Person):
def __init__(self,name, age, score):
super().__init__(name, age):
self.score = score
#######################
def info(self): # 重写
super().info() # 调用被重写的方法
print('学号:{0}'.fomat(self.score))
#######################
# 测试
stu = Student('Jack', 20, '1001')
stu.info
object类
- object类是所有类的一个父类,因此所有类都有object类的属性和方法
- 内置函数dir()可以查看指定对象的所有属性
- Object有一个__str__()方法,用于返回一个对于对象的描述,对应内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对__str__进行重写
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print('姓名:{0},年龄:{1}'.fomat(self.name, self.age))
def __str__(self):
return '姓名:{0},年龄:{1}'.fomat(self.name, self.age) # 重写父类方法
o = object()
p = Person('Jack', 20)
print(dir(0))
print(dir(p))
print(p) # 默认调用__str__方法来进行描述
多态
简单来说,多态的实现,多态就是拥有多种形态,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用的对象类型,动态决定调用那个对象的中的方法
class Animal(object):
def eat(self):
print('动物要吃东西')
class Dog(Animal):
def eat(self):
print('狗吃肉')
class Cat(Animal):
def eat(self):
print('猫吃鱼')
class Person(object):
def eat(self):
print('人吃五谷杂粮')
def fun(obj):
obj.eat() # 调用obj的eat()方法,只要对象具有这个方法
fun(Cat())
fun(Dog())
fun(Person())
- 静态语言实现多态的三个必要条件
- 继承
- 方法重写
- 父类引用指向子类对象
- 动态语言的多态崇尚'鸭子类型',当看到一只鸟走起路来像鸭子,游泳起来像鸭子,走起来也像鸭子,那么这只鸟就可以称做鸭子.在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为.
特殊方法和特殊属性
特殊属性
__dict__
:获得类对象或实例对象所绑定的所有属性和方法的字典(特殊属性)__class__
:输出对象所属于的类型__bases__
:输出父类类型的元素(多继承,多个)__base__
:输出父类类型的元素(优先的一个)__mro__
:输出类的层次结构__subclasses__
:输出子类的列表
特殊方法
__len__()
:(长度)通过重写__len__()方法,让内置函数len()的参数可以是自定义的类型__add__()
:(相加)通过重写__add__()方法,可使用自定义对象具有'+'的功能__new__()
:用于创建对象__init__()
:对创建的对象进行初始化
class Person(object):
def __new__(cls, *args, **kwargs):
print('__new__被调用执行了,cls的id值为:{0}'.format(id(cls)))
obj = super().__new__(cls)
print('创建的对象的id为:{0}'.format(id(obj)))
return obj
def __init__(self, name, age):
print('__init__被调用了,self的id为:{0}'.format(id(self)))
self.name = name
self.age = age
print('创建的类对象object的id为:{0}'.format(id(object)))
print('创建的类对象Person的id为:{0}'.format(id(Person)))
p1 = Person('张三', 20)
print('创建的Person类对象p1的id为:{0}'.format(id(p1)))
文件操作
编码格式的介绍
python的解释器使用的是Unicode(内存)
py文件在磁盘上使用的是UTF-8存储(外存)
文件的读写原理
- 文件的读写俗称'IO操作'(input/output)
- 文件的读写操作流程
- .py文件>解释器>os(操作系统)>硬盘
- 操作原理
- python操作文件
- 打开或新建文件
- 读,写文件
- 关闭资源
文件的读写操作
- 内置函数
open()
创建文件对象- 程序
- 对象(映射到磁盘上的真实文件)
- 通过IO流将磁盘文件的内容与程序中的对象中的内容进行同步
- 程序
file = open(文件名, mode, encoding)
'''
file是被创建的文件对象名,open()是创建对象的函数,文件名是要创建或打开的文件名称,mode对应打开模式(默认为只读),encoding对应字符的编码格式,默认文本文件的编写格式为gbk
上述参数都是字符串
'''
实例如下:
file = open('a.txt', 'r')
print(file.readlines())
file.close()
参数说明:常用的文件打开模式
- 文件的类型
- 按文件中数据的组织形式,文件分为以下两大类
- 文本文件:存储的是普通'字符'文本,默认是unicode字符集,可以使用记事本程序打开
- 二进制文件:把数据内容用'字节'进行储存,无法用记事本打开,必须用专用的软件打开,举例:mp3音频文件,jpg图片,doc文档
- 按文件中数据的组织形式,文件分为以下两大类
- 打开模式
- r:以只读模式打开文件,文件的指针将会放在文件的开头
- w:以只写模式打开文件,如果文件不存在则创建,如果文件存在,则覆盖原有内容,文件指针在文件的开头
- a:以追加模式打开文件,如果文件不存在则创建,文件指针在文件开头,如果文件存在,则在文件末尾追加内容,文件指针在原文件末尾
- b:以二进制方式打开文件,不能单独使用,需要与其他模式一起使用,rb或者wb
- +:以读写方式打开文件,不能单独使用,需要与其他模式一起使用,a+
文件对象的常用方法
- read(size):从文件中读取size个字节或字符的内容返回.若省略size,则读取到文件末尾,即一次读取文件所有内容
- readline():从文本文件中读取一行内容
- readlines():把文本文件中每一行都作为独立的字符串对象,并将这些对象放入列表中返回
- write(str):将字符串str内容写入文件
- writelines(s_list):把字符串列表s_list写入文本文件,不添加换行符
- seek(sffset, whence):把文件指针移动到新的位置,offset表示相对与whence的位置
- offset:为正往结束方向移动,为负往开始方向移动(字节)
- whence不同值代表不同含义:
- 0:从文件头开始计算
- 1:从当前位置开始计算
- 2:从文件尾开始计算
- tell():返回文件指针的当前位置
- flush():把缓冲区的内容写入文件,但不关闭文件
- close():把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源
with语句(上下文管理器)
- with语句可以自动管理上下文资源,不论是什么原因跳出with块,都能确保文件正确的关闭,以此来达到释放资源的目的
with open('a.txt', 'r') as file: # as 相当于起了个别名
print(file.read()) # with语句体
'''
open('a.txt', 'r')称为上下文表达式,它的结果是一个上下文管理器,同时创建了一个运行时上下文,可以自动调用__enter__()方法,并将返回值赋给file
- 上下文管理器
一个类对象实现了特殊方法__enter__()和__exit__(),那可以称这个对象遵循上下文管理器协议,而这个类的实例对象称为上下文管理器
'''
with open('a.jpg', 'rb') as src_file:
with open('b.jpg', 'rb') as target_file:
target_file.write(src_file.read())
'''
实现了将a.jpg复制到b.jpg的操作,同时上下文管理器自动关闭了文件,释放了资源
'''
目录操作
- os模块是python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样
- os模块与os.path模块用于对目录或文件进行操作
路径为字符串类型
# 类似于cmd
os.system('notepad.exe')
# 打开可执行文件(注意转义字符)
os.startfile(文件目录)
'''
os模块操作目录的相关函数(针对当前工作目录)
'''
# 遍历路径下所有文件(目录下的子目录也可以)并返回一个元组
os.walk(path)
# 返回当前的工作目录
os.getcwd()
# 返回指定路径下的文件和目录信息
os.listdir(path)
# 创建目录
os.mkdir(path[,mode])
# 创建多级目录
os.mkdirs(path1/path2/...[,mode])
# 删除目录
os.rmdir()
# 删除多级目录
os.removedirs(path1/path2/...)
# 将path设置为当前工作目录
os.chdir(path)
'''
os.path模块操作目录的相关函数
'''
# 用于获取文件或目录的绝对路径并返回
os.path.abspath(path)
# 用于判断文件或目录是否存在,如果存在返回True,不存在返回False
os.path.exists(path)
# 将目录与目录或者文件夹名拼接起来并返回
os.path.join(path, name)
# 分离文件名和拓展名并返回
os.path.splitext()
# 从一个目录中提取文件名并返回
os.path.basename(path)
# 从一个路径中提取文件路径,不包括文件名并返回
os.path.dirname(path)
# 用于判断是否为路径
os.path.isdir(path)
#用于判断是否为文件
os.path.isfile(path)
模块和包
- 模块(Modules)
- 一个模块可以包括N多个函数
- .py的文件就是一个模块
- 使用模块的好处
- 方便其他程序和脚本的导入和使用
- 避免函数名和变量名冲突
- 提高代码的可维护性
- 提高代码的可重用性
自定义模块
- 创建模块
- 新建一个.py的文件,名称尽量不要与python自带的标准模块相同(见名知意)
- 导入模块
import 模块名称 as 别名
from 模块名称 import 函数/变量/类
以主程序的形式运行
- 在每个模块的定义中都包含一个记录模块名称的变量__name__,程序可以检查该变量,以确定他们在哪个模块中执行
- 如果一个模块不是被导入到其他程序运行,那么他可能在解释器的顶级模块中执行
- 顶级模块中的_name_变量的值为_main_
if _name_ = '_main_':
pass
'''只有当前程序为主程序时,才会运行pass语句'''
python中的包
- 包是一个分层次的目录结构,他将一组功能相近的模块组织在一个目录下
- 作用:
- 代码规范
- 避免模块名称冲突
- 包和目录的区别
- 包含__init__.py文件的目录称为包
- 目录通常不包含__init__.py文件
- 包的导入
import 包名.模块名
from 包名/模块名/包名.模块名 import 模块名/函数/类/变量
python中的常用模块
- sys(与python解释器及其环境操作相关的标准库)
- time(提供了时间相关的各种函数的标准库)
- os(提供了访问操作系统服务功能的标准库)
- calender(提供与日期相关的各种函数的标准库)
- urllib(用于读取来自网上-服务器-的数据标准库)*爬虫
- json(用于使用json序列化和反序列化对象)*爬虫
- re(用于在字符串中执行正则表达式匹配和替换)*爬虫
- math(提供标准算数运算函数的标准库)
- decimal(用于进行精确控制计算精度,有效位数和四舍五入操作的十进制运算)
- logging(提供了灵活的记录事件,错误,警告和调试信息等日志信息的功能)
第三方模块的安装和使用
- 安装
pip install 模块名
- 使用 -
import 模块名
项目实战
- 需求分析
- 应该具有的功能
- 程序设计
- 思维导图
- 流程图
- 目录结构
- 开发环境
- 代码实现