Python基础
参考文章:算法乐园的Python笔记
基本概念
print函数
基本用法
最简单的用法就是直接打印一个字符串:
1 | print("Hello, World!") |
这将在控制台上输出:
1 | Hello, World! |
打印多个值
你也可以在一次print
调用中打印多个值,只需用逗号隔开它们:
1 | print("Hello,", "World!") |
输出:
1 | Hello, World! |
打印变量
当然,print
函数也可以用于打印变量的值:
1 | x = 10 |
输出:
1 | x = 10 , y = 20 |
换行与分隔符
默认情况下,print
函数会在每个值之间添加一个空格,并在最后添加一个换行符。你可以通过sep
和end
参数来自定义这些行为:
1 | print("Hello", "World", sep="-", end="!!!\n") |
输出:
1 | Hello-World!!! |
格式化字符串的语法
格式化字符串使用f
或F
前缀来标识,后面跟着一个字符串字面量,其中可以包含花括号{}
内的表达式。这些花括号内的表达式将在运行时被计算,并用其结果替换花括号。
基本用法
1 | name = "Alice" |
在上面的例子中,变量name
和age
被插入到了字符串中的相应位置。
input语句
基本用法
input()
函数的基本用法非常简单。当调用它时,程序会暂停并等待用户输入。用户可以在命令行或交互式环境中输入文本,然后按Enter键提交输入。
下面是一个简单的例子:
1 | user_input = input("请输入一些文本:") |
在这个例子中,程序首先打印出提示信息”请输入一些文本:”,然后等待用户输入。用户输入的内容将被赋值给变量user_input
,然后程序打印出”你输入的是:”后面跟着用户输入的内容。
输入类型
需要注意的是,input()
函数返回的总是一个字符串类型。即使你输入的是一个数字,它也会被当作字符串处理。如果你需要将输入转换为其他类型(如整数或浮点数),你需要使用相应的类型转换函数。
注释
单行注释
Python 中的单行注释以 #
开头。#
符号后面的所有内容都会被视为注释,直到该行的结束。
1 | # 这是一个单行注释 |
多行注释
Python 本身并没有直接支持多行注释的语法,但我们可以使用三重引号("""
或 '''
)来实现类似的效果。三重引号通常用于多行字符串,但如果没有将它们赋值给变量或用作其他目的,它们也可以用作多行注释。
1 | """ |
语句
Python 中一般以新行作为语句的结束标识,可以使用 \ 将一行语句分为多行显示。如下所示:
1 | a = 128 |
如果包含在 []、{}、() 括号中,则不需要使用 \。如下所示:
1 | arr = { |
Python变量及基本数据
类型介绍
在Python编程语言中,数据类型是一个重要的概念,它决定了变量可以保存何种类型的数据以及可以对这些变量执行哪些操作。Python有几种基本(或内置)的数据类型,包括整数(int)、浮点数(float)、字符串(str)等,但请注意字符(char)这一概念在Python中并不作为一个独立的基本数据类型存在,字符通常被视为长度为1的字符串。
1. 整数(Integers)
整数是没有小数部分的数字,可以是正数或负数。在Python中,整数的大小只受限于可用内存。
1 | x = 10 # 定义一个整数 |
Python 3中的整数是动态大小的,意味着Python整数可以处理任意大小的整数,只要内存允许。
2. 浮点数(Floating Point Numbers)
浮点数是有小数点的数字,它们用于表示实数。
1 | x = 1.23 # 定义一个浮点数 |
浮点数在计算机中的表示是近似的,因此在进行浮点数运算时要特别注意精度问题。
3. 字符串(Strings)
字符串是由零个或多个字符组成的有序字符序列。在Python中,字符串是不可变的。
1 | s1 = "Hello" # 定义一个字符串 |
字符串可以通过连接(concatenation)形成新的字符串,也可以用切片(slicing)来访问子字符串。
4. 字符(Characters)
在Python中,并没有专门的“字符”数据类型。相反,字符被视为长度为1的字符串。你可以通过索引字符串来获取单个字符。
1 | s = "Hello" |
在这个例子中,char
实际上是一个长度为1的字符串,它包含了字符 ‘H’。在Python中处理单个字符时,你通常会使用长度为1的字符串。
变量
1 | # 定义一个变量money,并赋值为10 |
查看数据类型
可以使用type()
函数来查看一个变量的数据类型。
1 | # 定义几个变量,并分别赋予不同的数据类型 |
运行这段代码,你会得到输出<class 'str'> <class 'int'> <class 'float'>
,说明这三个变量的数据类型分别是字符串、整数和浮点数。
数据类型转换
在Python中,你可以使用内置的函数来进行数据类型之间的转换。常见的转换函数有int()
、float()
和str()
。
int(x)
:将x转换为一个整数。如果x是一个浮点数,会舍去小数部分。如果x是一个字符串,且字符串内容可以转换为整数,则会转换为相应的整数;否则会报错。float(x)
:将x转换为一个浮点数。如果x是一个整数,会在其后面添加.0
。如果x是一个字符串,且字符串内容可以转换为浮点数,则会转换为相应的浮点数;否则会报错。str(x)
:将x转换为一个字符串。无论x是什么数据类型,都会转换为其对应的字符串形式。
1 | # 将浮点数转换为字符串 |
运行这段代码,你会得到以下输出:
1 | <class 'str'> 114.514 |
注意在进行数据类型转换时,要确保转换是合法的,否则程序会报错。例如,尝试将一个包含非数字字符的字符串转换为整数或浮点数会导致ValueError
。
标识符
标识符命名只允许出现:(和C++一样)
- 英文字母
- 中文(不推荐)
- 数字(不可以开头)
- 下划线_
处理数据类型
Python的运算符介绍
1. 算术运算符
算术运算符用于执行基本的数学运算。
+
:加法运算符,用于计算两个数的和。-
:减法运算符,用于计算两个数的差。*
:乘法运算符,用于计算两个数的积。/
:除法运算符,用于计算两个数的商。(python两个整数相除会得到浮点数)//
:整除运算符,用于计算两个数整除后的结果(只保留整数部分)。整除取整方向默认为$−∞$。%
:取模运算符,用于计算两个数相除后的余数。**
:幂运算符,用于计算一个数的幂。
2. 比较运算符
比较运算符用于比较两个值的大小关系,返回一个布尔值(True或False)。
==
:等于运算符,用于判断两个值是否相等。!=
:不等于运算符,用于判断两个值是否不相等。>
:大于运算符,用于判断左侧的值是否大于右侧的值。<
:小于运算符,用于判断左侧的值是否小于右侧的值。>=
:大于等于运算符,用于判断左侧的值是否大于或等于右侧的值。<=
:小于等于运算符,用于判断左侧的值是否小于或等于右侧的值。
3. 逻辑运算符
逻辑运算符用于组合多个条件表达式,返回一个布尔值。
and
:逻辑与运算符,当所有条件都为True时,返回True。or
:逻辑或运算符,当至少有一个条件为True时,返回True。not
:逻辑非运算符,用于取反一个布尔值。Python中的逻辑判断:与、或、非
在Python中,逻辑运算符用于连接布尔表达式,并根据这些表达式的真假值返回结果。与Java等其他语言相比,Python的逻辑运算符有一些独特之处,特别是在处理非布尔类型的值时。
逻辑运算符
Python中的逻辑运算符包括:
and
:逻辑与or
:逻辑或not
:逻辑非
逻辑运算符的行为
逻辑与 (
and
)当使用
and
运算符时:- 如果所有表达式的值都为真(非零、非空等),则返回最后一个表达式的值。
- 如果有一个或多个表达式的值为假(零、空等),则返回第一个假值。
逻辑或 (
or
)当使用
or
运算符时:- 如果有一个或多个表达式的值为真,则返回第一个真值。
- 如果所有表达式的值都为假,则返回最后一个假值。
逻辑非 (
not
)not
运算符返回表达式的布尔否定值。如果表达式为真,则返回False
;如果表达式为假,则返回True
。示例
下面是一些Python逻辑运算符的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13# 逻辑与 (and)
print(3 > 2 and 3 > 1) # True,因为两个条件都为真
print(3 and 2) # 2,因为3为真,返回第二个值2
print(0 and None) # 0,因为0为假,返回第一个假值0
# 逻辑或 (or)
print(3 > 2 or 3 > 1) # True,因为至少有一个条件为真
print(2 or 3 > 2) # 2,因为2为真,返回第一个真值2
print(0 or None) # None,因为两者都为假,返回最后一个假值None
# 逻辑非 (not)
print(not 3) # False,因为3为真值
print(not 0) # True,因为0为假值为假的值
在Python中,以下值在布尔上下文中被视为
False
:- 数值类型中的
0
和0.0
- 空序列类型,如空字符串
''
、空列表[]
、空元组()
、空字典{}
None
对象- 布尔类型本身的
False
值
需要注意的是,当这些“假值”作为逻辑表达式的一部分时,它们本身会被返回作为结果,而不是布尔值
False
。这是Python逻辑运算符与其他语言(如Java)的一个主要区别。在Java中,逻辑运算符只能用于布尔表达式,并且结果总是布尔值。而在Python中,逻辑运算符可以更加灵活地用于不同类型的值,并返回这些值本身作为结果。这种特性使得Python代码在某些情况下可以更加简洁和高效。但同时也需要注意逻辑运算符的这种行为可能会带来的潜在混淆和错误。因此在使用时需要特别小心并确保理解其行为规则。
4. 位运算符
位运算符用于对二进制位进行操作。
&
:按位与运算符,对两个数的二进制位进行与操作。|
:按位或运算符,对两个数的二进制位进行或操作。^
:按位异或运算符,对两个数的二进制位进行异或操作。~
:按位取反运算符,对一个数的二进制位进行取反操作。<<
:左移运算符,将一个数的二进制位向左移动指定的位数。>>
:右移运算符,将一个数的二进制位向右移动指定的位数。
5. 赋值运算符
赋值运算符用于将表达式的值赋给变量。
=
:赋值运算符,将右侧表达式的值赋给左侧的变量。+=
:加法赋值运算符,将右侧的值加到左侧的变量上,并将结果赋给左侧的变量。-=
:减法赋值运算符,将右侧的值从左侧的变量中减去,并将结果赋给左侧的变量。*=
:乘法赋值运算符,将右侧的值与左侧的变量相乘,并将结果赋给左侧的变量。/=
:除法赋值运算符,将左侧的变量除以右侧的值,并将结果赋给左侧的变量。%=
:取模赋值运算符,将左侧变量与右侧值进行取模运算,并将结果赋给左侧的变量。**=
:幂赋值运算符,将左侧变量进行幂运算后的结果赋给左侧的变量。//=
:整除赋值运算符,将左侧变量与右侧值进行整除运算后的结果赋给左侧的变量。
6. 身份运算符
身份运算符用于比较两个对象的身份是否相同。
is
:判断两个标识符是否引用同一个对象。is not
:判断两个标识符是否引用不同的对象。
7. 成员运算符
成员运算符用于判断一个值是否存在于序列中(如列表、元组、字符串等)。
in
:如果指定的值在序列中找到,则返回True,否则返回False。not in
:如果指定的值没有在序列中找到,则返回True,否则返回False。
这些运算符在Python编程中非常常用,掌握它们对于编写高效的Python代码至关重要。
字符串操作
字符串拼接
在Python中,你可以使用加号(+
)操作符来拼接(连接)两个或多个字符串。
1 | s1 = "abcd" |
字符串格式化
Python 提供了多种方式来格式化字符串,其中 %
操作符是一种较旧的方法,但在某些情况下仍然很有用。
1 | # 使用%s作为字符串占位符,%d作为整数占位符,%f作为浮点数占位符 |
注意:%.1f
表示浮点数将被格式化为小数点后保留一位。
字符串格式化的一种快速写法
格式:f”内容{变量}”
(不关心精度控制)
1 | s = "绩点" |
字符转ASCII和ASCII转字符串
在Python中,你可以使用 ord()
函数将一个字符转换成其对应的ASCII数值,使用 chr()
函数将一个ASCII数值转换成对应的字符。
1 | print(ord("a")) # 输出:97 |
字符串的大小写转化
Python 提供了几种方法来改变字符串的大小写。
1 | # 使用 title() 方法将字符串中每个单词的首字母变成大写,其余小写 |
注意:这些方法都不会改变原始字符串,而是返回一个新的字符串。因为Python中的字符串是不可变的。
浮点数精度控制
使用%格式化浮点数
下面是一些使用%
运算符和.yf
格式来格式化浮点数的例子:
1 | # 定义一个浮点数 |
条件与循环
1. 条件语句
1.1 布尔类型
布尔类型(bool)用于表示逻辑值,其中 True
表示真(逻辑上的1),False
表示假(逻辑上的0)。
1.2 条件表达式
条件表达式的结果是布尔类型。例如,比较运算符(如 >
、<
、==
等)的结果就是布尔类型。
1 | num1 = 11 |
1.3 if-elif-else 语句
if-elif-else
语句用于根据条件执行不同的代码块。
1 | num = int(input("请输入一个数字:")) |
在这个例子中,根据输入的数字大小,程序会输出不同的结果。注意要写$:$
1.4 pass 语句
pass
是一个空语句,它不做任何事情。它通常用作占位符,以保持程序结构的完整性。
1 | num = int(input("请输入一个数字:")) |
2. 循环语句
2.1 while 循环
while
循环会重复执行一段代码,直到条件不再满足为止。
1 | x = 1 |
2.2 for 循环
for
循环用于遍历序列类型(如字符串、列表、元组等)中的元素。
1 | s = "abcdef" |
2.3 range() 函数
range()
函数用于生成一个数字序列。它有三种用法:
range(num)
:生成从 0 开始到 num-1 的数字序列。range(num1, num2)
:生成从 num1 开始到 num2-1 的数字序列。range(num1, num2, step)
:生成从 num1 开始到 num2-1 的数字序列,步长为 step。
1 | # 使用 range() 函数的例子 |
函数
函数定义与调用
在Python中,函数是通过def
关键字定义的,后面跟函数名和括号内的参数列表。函数体由一系列语句组成,并且使用缩进来表示。
1 | def function_name(parameters): |
调用函数时,需要在函数名后加上括号和必要的参数。
1 | result = function_name(arguments) # 调用函数,并将返回值存储在变量中(如果有返回值的话) |
注:Python不支持函数重载
函数的返回值
如果函数中有return
语句,那么函数会返回return
后面的值。如果函数中没有return
语句或者return
语句后面没有跟任何值,那么函数会默认返回None
。
多返回值
在Python中,函数不仅可以返回单个值,还可以返回多个值。
函数多返回值
当函数需要返回多个值时,可以将这些值以逗号分隔放在return
语句后。这些值会被打包成一个元组返回。调用函数时,可以使用多个变量来接收这些返回值。
1 | def test01(): |
函数也可以返回不同类型的值:
1 | def test02(): |
函数的参数传递
位置参数
位置参数是按照函数声明中参数的顺序来传递的。
1 | def test03(name, age, gender): |
关键字参数
关键字参数是通过参数名来指定要传递的参数值。关键字参数可以不按照函数声明中的顺序来传递,但是要注意在函数调用时关键字参数的名称必须与函数声明中的参数名一致。
1 | def test04(name, age, gender): |
关键字参数和位置参数可以混用,但位置参数必须放在关键字参数前面。
1 | def test05(name, age, gender): |
缺省参数
缺省参数是指在函数声明时为参数指定一个默认值。如果在函数调用时没有为该参数传递值,则使用默认值。缺省参数必须放在函数声明的最后。
1 | def test06(name, age, gender="Male"): |
不定长参数
不定长参数是指函数可以接受任意数量的参数。在函数声明中,使用*args
来表示接受任意数量的位置参数,使用**kwargs
来表示接受任意数量的关键字参数。这些参数在函数内部被收集为一个元组或一个字典。
位置传递(*args)
1 | def test07(*args): |
关键字传递(**kwargs)
1 | def test08(**kwargs): |
局部变量与全局变量
在函数内部定义的变量是局部变量,只能在该函数内部访问。在函数外部定义的变量是全局变量,可以在任何地方访问,包括函数内部(除非被局部变量覆盖)。
如果需要在函数内部修改全局变量,需要使用global
关键字声明。
函数说明文档(Docstring)
函数说明文档是一种特殊的注释,用于解释函数的作用、参数和返回值。它位于函数定义的开始,由三个双引号(可以是三个单引号)包围。
Docstring可以通过help()
函数或者函数的__doc__
属性查看。
示例代码
下面是一个包含函数定义、调用、局部变量、全局变量和Docstring的示例代码:
1 | # 全局变量 |
Python中的数据结构
List——列表
定义列表
在Python中,列表(List)是一种可变的数据容器,可以包含任意类型的对象:数字、字符串、其他列表等。列表中的元素通过逗号分隔,并包含在方括号 []
中。
1 | # 定义一个字符串列表 |
下标索引
列表中的元素可以通过下标索引来访问。在Python中,下标从0开始。
1 | my_list = ["abc", "def", "ghi"] |
尝试访问超出范围的索引会导致IndexError
。
查找元素
在Python中,你可以使用list.index()
函数来查找列表中某个元素的索引。这个函数会返回元素在列表中首次出现的索引,如果元素不在列表中,则会抛出一个ValueError
异常。
下面是一个基本的使用示例:
1 | # 定义一个列表 |
这段代码会输出:
1 | bash复制代码 |
因为在这个列表中,’banana’的索引是1(索引是从0开始的)。
修改元素
列表中的元素可以通过下标索引来修改。
1 | my_list = ["abc", "def", "ghi"] |
插入元素
.insert()方法
使用.insert()
方法可以在列表的指定位置插入一个元素。
1 | my_list = ["abc", "def", "ghi"] |
.append()方法
使用.append()
方法可以在列表的末尾追加一个元素。
1 | my_list = ["abc", "def", "ghi"] |
.extend()方法
使用.extend()
方法可以在列表的末尾追加另一个容器(例如列表)的所有元素。
1 | my_list = ["abc", "def", "ghi"] |
删除元素
del语句
使用del
语句可以删除列表中指定位置的元素。
1 | my_list = ["abc", "def", "ghi", "jkl"] |
.pop()方法
使用.pop()
方法可以删除并返回列表中指定位置的元素。如果不提供索引,则默认删除并返回最后一个元素。
1 | my_list = ["abc", "def", "ghi", "jkl"] |
.remove()方法
使用.remove()
方法可以删除列表中第一个出现的指定元素。如果元素不存在于列表中,则会导致ValueError
。
1 | my_list = ["abc", "def", "ghi", "jkl"] |
清空列表
使用.clear()
方法可以清空列表中的所有元素。
1 | my_list = ["abc", "def", "ghi", "jkl"] |
统计元素数量
使用.count()
方法可以统计列表中某个元素出现的次数。
1 | my_list = [1, 2, 3, 2, 1] |
列表长度
使用内置函数len()
可以获取列表的长度(即元素的数量)。
1 | my_list = [1, 2, 3, 4, 5] |
遍历容器
可以使用for
循环来遍历列表中的元素。
1 | my_list = [1, 2, 3, 4, 5] |
如果需要在遍历过程中同时获取元素的下标和值,可以使用enumerate()
函数。
1 | my_list = ["apple", "banana", "cherry"] |
这将输出:
1 | 1 apple |
如果start=0,将输出
1
2
3 >0 apple
1 banana
2 cherry
Python中列表的拷贝方法
在Python中,拷贝一个列表可以有多种方法,但每种方法都有其特定的用途和后果。本笔记将详细介绍使用赋值运算符(=
)、.copy()
方法,以及copy
模块中的deepcopy()
函数进行列表拷贝的区别。
1. 赋值运算符(=
)
使用赋值运算符并不是真正的拷贝,而是创建了一个新的引用指向同一个列表对象。
1 | list1 = [1, 2, 3, [4, 5]] |
在这种情况下,list1
和list2
实际上是指向内存中同一个对象的两个不同名字。任何对list2
的修改都会反映到list1
上,反之亦然。
1 | list2.append(6) # 修改list2 |
2. .copy()
方法(浅拷贝)
Python的列表对象有一个.copy()
方法,用于创建列表的浅拷贝。这意味着它创建了列表的一个新副本,但副本中的元素仍然是原始列表中元素的引用。
1 | list1 = [1, 2, 3, [4, 5]] |
现在,list1
和list2
是两个不同的列表对象,但它们的元素(特别是可变对象,如内部列表)仍然是共享的。
1 | list2[3][0] = 'four' # 修改list2中的内部列表 |
尽管list1
和list2
是不同的列表对象,但由于浅拷贝的性质,它们共享对内部列表的引用。
3. deepcopy()
函数(深拷贝)
要创建一个完全独立的列表拷贝,包括其所有嵌套对象,应使用copy
模块中的deepcopy()
函数。深拷贝会递归地复制对象及其所有子对象,生成一个全新的对象树。
1 | import copy |
现在,list2
是list1
的一个完全独立的拷贝,包括所有嵌套对象。
1 | list2[3][0] = 'four' # 修改list2中的内部列表 |
修改list2
不会影响list1
,因为deepcopy()
创建了所有对象的独立拷贝。
总结
- 赋值运算符(
=
)不创建拷贝,只创建引用。 .copy()
方法执行浅拷贝,创建新列表但共享嵌套对象。deepcopy()
函数执行深拷贝,递归地复制所有对象,生成完全独立的对象树。
tuple——元组
和list的区别是不可修改
元组(Tuple)是Python中的一种不可变序列类型,用于存储一系列有序的元素。与列表(List)不同,元组一旦定义,就不能再修改其内容。元组通常用于存储不应该被改变的数据集合。
定义元组
元组使用圆括号()
来定义,元素之间使用逗号,
分隔。例如:
1 | # 定义一个包含多个元素的元组 |
注意,如果元组只包含一个元素,那么该元素后面必须跟一个逗号,否则它不会被识别为元组。例如:
1 | # 定义一个包含单个元素的元组(注意逗号) |
元组的不可变性
元组是不可变的,这意味着一旦创建了一个元组,你就不能添加、删除或更改其元素。尝试这样做会导致TypeError。
1 | my_tuple = (1, 2, 3) |
然而,如果元组中包含可变对象(如列表),那么这些对象的内容是可以被修改的。但请注意,你不能更改这些可变对象在元组中的身份(即不能用一个新的列表替换原有的列表)。
1 | # 元组中包含一个列表 |
在实际应用中,如果你需要一个不可变的序列来存储数据,并且这些数据在程序的整个生命周期中都不会改变,那么使用元组是一个很好的选择。元组的不可变性也使其在某些情况下比列表更加高效,因为Python可以在内部对其进行优化。
string——字符串
字符串(String)是 Python 中常见的数据容器之一,用于存储字符序列。字符串具有一些独特的特点和操作方法。
字符串的访问
字符串中的字符可以通过下标进行访问。下标从0开始递增,表示从前往后访问字符;而从-1开始递减,则表示从后往前访问字符。
1 | s = "Hello, World!" |
字符串的不可变性
同元组(Tuple)一样,字符串是一个无法修改的数据容器。一旦一个字符串被创建,就不能修改它的内容。任何对字符串的修改操作都会生成一个新的字符串对象。
字符串方法
index 方法
index
方法用于查找子字符串在字符串中首次出现的位置,并返回该位置的索引。如果子字符串不存在,则会抛出异常。
1 | s = "you are a handsome boy" |
replace 方法
replace
方法用于将字符串中的某个子字符串替换为另一个字符串,并返回替换后的新字符串。原始字符串本身不会被修改。
1 | s = "cats and dogs are good cats and dogs and cats and dogs do things cats and dogs like do" |
split 方法
split
方法用于根据指定的分隔符将字符串分割成多个子字符串,并将这些子字符串存储在列表中返回。原始字符串本身不会被修改。
1 | s = "cats and dogs are good cats and dogs and cats and dogs do things cats and dogs like do" |
strip 方法
strip
方法用于去除字符串开头和结尾的空白字符(包括空格、制表符、换行符等),并返回处理后的新字符串。原始字符串本身不会被修改。如果指定了参数,则会去除前后指定的字符。
1 | s = " 12abcde1 " |
count 方法
count
方法用于统计某个子字符串在字符串中出现的次数,并返回该次数。
1 | s = "114514514114514514114114" |
len 函数
len
函数用于获取字符串的长度,即字符的个数。
1 | s = "114514514114514514114114" |
请注意,虽然 len
是一个内置函数而不是字符串的方法,但它经常用于获取字符串的长度,因此在这里也一并提及。
Python 中常用处理字符串的相关函数
在Python中,字符串是不可变的,但Python提供了很多方法来操作字符串。这些方法可以帮助我们完成各种任务,如查找子字符串,替换子字符串,分割字符串等。下面列出了一些Python中常用的字符串方法:
字符串首字母大写
string.capitalize()
该方法返回字符串的一个副本,其中第一个字符为大写,其余为小写。
计数子字符串
string.count(str, beg=0, end=len(string))
该方法返回子字符串在字符串中出现的次数。可选参数beg
和end
是字符串中要开始和结束搜索的索引范围。
检查字符串结束
string.endswith(obj, beg=0, end=len(string))
该方法检查字符串是否以指定的后缀结束,如果是则返回True
,否则返回False
。可选参数beg
和end
指定需要检查的字符串的子集。
查找子字符串
string.find(str, beg=0, end=len(string))
该方法检测字符串中是否包含子字符串str
,如果包含则返回开始的索引值,否则返回-1。搜索可以指定开始和结束的索引范围。
类似find但异常
string.index(str, beg=0, end=len(string))
与find()
方法类似,但如果子字符串不在字符串中,则会引发一个异常。
检查字母和数字
string.isalnum()
:如果字符串至少有一个字符并且所有字符都是字母或数字,则返回True
。string.isalpha()
:如果字符串至少有一个字符并且所有字符都是字母,则返回True
。string.isdecimal()
:如果字符串只包含十进制数字,则返回True
。string.isdigit()
:如果字符串只包含数字,则返回True
。
检查大小写
string.islower()
:如果字符串中包含至少一个区分大小写的字符,并且所有这些字符都是小写,则返回True
。string.isupper()
:如果字符串中包含至少一个区分大小写的字符,并且所有这些字符都是大写,则返回True
。
其他检查
string.isnumeric()
:如果字符串中只包含数字字符,则返回True
。string.isspace()
:如果字符串中只包含空格,则返回True
。string.istitle()
:如果字符串是标题化的(即每个单词的首字母大写),则返回True
。
连接字符串
string.join(seq)
该方法以指定的字符串作为分隔符,将序列中的元素连接成一个新的字符串。
使用加号 +
运算符
1 | str1 = "Hello" |
在这个例子中,我们使用了 +
运算符和空格字符串来连接 str1
和 str2
。
转换大小写
string.lower()
:将字符串中的所有大写字符转换为小写。string.upper()
:将字符串中的所有小写字符转换为大写。
去除空格
string.lstrip()
:删除字符串左边的空格。string.rstrip()
:删除字符串右边的空格(注:该方法未在上文列出,但经常与lstrip()
一起使用)。string.strip([obj])
:在字符串上同时执行lstrip()
和rstrip()
,删除两端的空格或指定字符。
替换子字符串
string.replace(str1, str2, num=string.count(str1))
该方法把字符串中的str1
替换成str2
,如果指定了num
,则替换不超过num
次。
分割字符串
string.split(str="", num=string.count(str))
该方法以指定的分隔符切片字符串,如果指定了num
,则仅分隔出num+1
个子字符串。
检查字符串开始
string.startswith(obj, beg=0, end=len(string))
该方法检查字符串是否以指定的前缀开始,如果是则返回True
,否则返回False
。
交换大小写
string.swapcase()
该方法翻转字符串中的大小写,即大写变小写,小写变大写。
标题化字符串
string.title()
该方法返回“标题化”的字符串,即所有单词的首字母大写,其余小写。
需要注意的是,字符串的方法很多,而且功能强大,但这里只列出了一些常用的方法。在实际编程中,可以根据需要选择合适的方法来操作字符串。
序列的切片
序列是内容连续、有序,且可以使用下标索引的一类数据容器。在Python中,列表、元组、字符串均可以视为序列。
对序列进行切片操作可以得到序列的一个子序列。切片操作使用冒号(:
)分隔的下标索引来实现,基本语法为sequence[start:end:step]
,其中:
sequence
表示要进行切片操作的序列。start
表示切片操作的起始位置(包含该位置),如果省略则表示从头开始。end
表示切片操作的结束位置(不包含该位置),如果省略则表示直到序列末尾。step
表示切片操作的步长,即每隔多少个元素取一个,如果省略则表示步长为1。
注意,切片操作不会影响序列本身,而是会得到一个新的序列。
示例
列表切片
1 | mylist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
元组切片
元组的切片操作与列表类似。
1 | mytuple = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) |
字符串切片
字符串也可以进行切片操作,得到一个新的字符串。
1 | mystring = "Hello, World!" |
Set——集合
集合是一个无序的、不重复的数据集合。在Python中,集合用花括号{}
或者set()
函数创建,但由于花括号{}
同时用于表示字典,所以空集合必须用set()
表示,而不是{}
。
集合的创建与特性
1 | # 使用花括号创建集合(非空集合) |
集合的修改
集合是可变的,可以添加或删除元素。
添加元素
使用.add()
方法向集合添加元素。
1 | a = {11, 2, 3, 4, 5, 6, 7} |
移除元素
使用.remove()
方法从集合中移除指定元素;使用.pop()
方法随机移除并返回集合中的一个元素。
1 | a = {11, 2, 3, 4, 5, 6, 7} |
集合运算
差集
使用.difference()
方法可以得到两个集合的差集,即存在于第一个集合但不存在于第二个集合的元素。
1 | set1 = {1, 2, 3, 4, 5} |
差集并更新左集合
使用.difference_update()
方法可以直接更新左集合为差集结果。
1 | set1 = {1, 2, 3, 4, 5} |
并集
使用.union()
方法可以得到两个集合的并集,即两个集合中所有不重复的元素。
1 | set1 = {1, 2, 3} |
集合的长度
使用len()
函数可以得到集合中元素的数量。
1 | a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9} |
集合的遍历
由于集合不支持下标索引,所以不能使用while
循环通过下标来遍历集合。但可以使用for
循环直接遍历集合中的元素。
1 | set1 = {1, 2, 3, 4, 5} |
字典——dict
字典(dict)是Python中的一种基本数据结构,用于存储键值对(key-value pairs)。字典是无序的,即元素的插入顺序和迭代顺序可能不一致。字典的键(key)必须是不可变的类型,如整数、浮点数、字符串、元组等,而值(value)可以是任意Python对象。
创建字典
字典可以通过大括号 {}
或 dict()
函数来创建。大括号中,键值对之间用冒号分隔,每对键值对之间用逗号分隔。
1 | d1 = {"a": 97, "b": 98, "c": 99, "d": 100} |
访问字典元素
字典中的元素可以通过键来访问。使用方括号 []
和键名来获取对应的值。
1 | d1 = {"a": 97, "b": 98, "c": 99, "d": 100} |
新增和更新字典元素
可以通过方括号 []
来新增或更新字典中的元素。如果键已经存在,则对应的值会被更新;如果键不存在,则会在字典中新增一个键值对。
1 | d1 = {"a": 97, "b": 98} |
需要注意的是,字典不支持访问不存在的键,否则会抛出KeyError
异常。如果尝试访问不存在的键,可以使用get()
方法,该方法允许指定一个默认值。
1 | d1 = {"a": 97, "b": 98} |
删除字典元素
可以使用pop()
方法来删除字典中的元素,并返回被删除元素的值。如果尝试删除不存在的键,pop()
方法会抛出KeyError
异常,但可以通过提供第二个参数来指定一个默认值。
1 | d1 = {"a": 97, "b": 98, "c": 99} |
另外,clear()
方法可以清空字典中的所有元素。
1 | d1.clear() # 清空字典 |
获取字典的键和值
可以使用keys()
方法获取字典中所有的键,values()
方法获取所有的值。这两个方法返回的都是视图对象,它们会反映字典的任何更改。
1 | d1 = {"a": 97, "b": 98, "c": 99} |
遍历字典
字典可以通过多种方式进行遍历。最常见的是遍历所有的键,然后使用键来访问对应的值。
1 | d1 = {"a": 97, "b": 98, "c": 99} |
还可以直接遍历字典的项(键值对),这可以通过items()
方法来实现。
1 | for key, value in d1.items(): |
统计字典元素数量
使用len()
函数可以获取字典中元素的数量(键值对的数量)。
1 | d1 = {"a": 97, "b": 98, "c": 99} |
判断元素是否在字典内
可以使用in
关键字来判断一个键是否存在于字典中。同样地,not in
可以用来判断一个键是否不存在于字典中。
1 | d1 = {"a": 97, "b": 98, "c": 99} |
容器常用功能
容器之间的转换
转换为列表(list)
在Python中,列表(list)是一种非常常用的数据结构,它可以容纳不同类型的元素,包括数字、字符串、元组、集合甚至字典等。Python提供了便捷的方式将这些容器类型转换为列表。
从元组(tuple)转换
元组与列表非常相似,但元组是不可变的。我们可以使用list()
函数将元组转换为列表。
1 | a1 = (1, 2, 3, 4, 5) |
从字符串(string)转换
字符串可以被看作字符的序列,因此也可以被转换为列表,每个字符成为列表的一个元素。
1 | b1 = "abcdefg" |
从集合(set)转换
集合是一个无序的不重复元素集,转换为列表后会得到一个包含集合中所有元素的列表。
1 | c1 = {1, 2, 3, 4, 5} |
从字典(dictionary)转换
字典转换为列表时,默认只包含字典的键(key)。
1 | d1 = {"a": 97, "b": 98, "c": 99, "d": 100, "e": 101, "f": 102} |
如果想要同时获取键和值,可以使用items()
方法,它会返回一个包含键值对的元组列表。
1 | print(list(d1.items())) # 输出: [('a', 97), ('b', 98), ('c', 99), ('d', 100), ('e', 101), ('f', 102)] |
转换为其他类型
当然,Python也允许我们将列表转换为其他类型,如元组、字符串、集合等。
转换为元组(tuple)
使用tuple()
函数可以将列表转换为元组。
1 | lst = [1, 2, 3, 4, 5] |
转换为字符串(string)
在Python中,将列表转化为字符串可以通过多种方式实现。最常见的方法是使用 join()
方法,它可以将列表中的元素连接起来形成一个字符串。以下是一个简单的示例:
1 | my_list = ['Hello', 'world', 'this', 'is', 'a', 'list'] |
转换为集合(set)
使用set()
函数可以将列表转换为集合,从而去除重复元素。
1 | lst = [1, 2, 2, 3, 4, 4, 5] |
排序功能(sorted)
Python的sorted()
函数可以对任何可迭代对象进行排序,并返回一个列表。默认情况下,排序是升序的,但可以通过reverse=True
参数进行降序排序。
1 | a1 = (5, 6, 2, 4, 0) |
对于字符串和字典的排序,sorted()
函数会根据元素的字符顺序或键的顺序进行排序。如果想要根据其他标准进行排序,可以使用key
参数指定一个函数来提取用于排序的值。
头等函数
函数作为参数传递
在Python中,函数是对象,可以像其他对象一样被传递作为参数。这种能力使得函数变得更加灵活和强大。你可以将函数作为参数传递给其他函数,或者从其他函数中返回函数。
函数作为参数的示例
1 | def test_func(compute): |
输出结果:
1 | 3 |
在这个例子中,test_func
接收一个名为compute
的函数作为参数,并使用它来计算1和2的和。然后打印结果和compute
的类型,显示为<class 'function'>
,表明compute
确实是一个函数对象。
使用lambda匿名函数作为参数
lambda函数是一种简洁的写函数的方式,它可以在一行内定义简单的函数。lambda函数是匿名的,因为它们没有正式的函数名,但可以将它们赋值给变量,或者以其他方式使用,例如作为函数的参数。
1 | def test_func(compute): |
输出结果:
1 | 3 |
这里,我们创建了一个lambda函数lambda x, y: x + y
,它接收两个参数x
和y
,并返回它们的和。然后我们将这个lambda函数作为参数传递给test_func
。输出与前面的例子相同,因为lambda函数的行为与add
函数相同。
请注意,在lambda函数中,虽然我们没有明确写出return
关键字,但表达式x + y
的结果会被自动返回。这是lambda函数的一个特点:它们总是返回表达式的结果。
在Python中,lambda
函数是设计为单行表达式函数的,它们只能包含一个表达式,该表达式的值会被返回。因此,lambda
函数不支持多行语句或多条指令。如果你想定义一个多行的函数,你应该使用def
关键字来定义一个常规函数。
模块
模块的概念
在Python中,模块(Module)是一个包含Python定义和语句的文件。文件名就是模块名加上.py
后缀。模块可以被其他程序引入,以使用该模块中的函数、类等功能。模块可以包含可执行的语句和定义函数、类和变量。模块让你能够有逻辑地组织你的Python代码段,实现代码重用。
模块的导入
1. 使用import
语句导入整个模块
你可以使用import
语句导入整个模块,并通过模块名来访问其中的函数、类、变量等。
1 | import time # 导入整个time模块 |
2. 使用from ... import ...
语句导入模块中的特定部分
如果你只需要模块中的某个函数或类,可以使用from ... import ...
语句将其导入到当前命名空间中。
1 | from time import sleep # 只导入time模块中的sleep函数 |
3. 使用from ... import *
语句导入模块中的所有内容
虽然这种方式可以导入模块中的所有内容,但通常不推荐使用,因为它可能导致命名冲突和不可预见的行为。
1 | from time import * # 导入time模块中的所有内容(不推荐) |
给模块起别名
如果模块名太长或与其他模块名冲突,你可以使用as
关键字给模块起一个别名。
1 | import time as t # 给time模块起别名为t |
给函数起别名
同样地,你也可以使用as
关键字给导入的函数起别名。
1 | from time import sleep as sl # 给sleep函数起别名为sl |
定义自己的模块
自定义模块
在Python中,模块是一个包含Python定义和语句的文件。文件名是模块名加上.py
后缀。模块可以被其他程序引入,以使用该模块中的函数、类等。在本例中,我们将创建一个简单的模块,并展示如何在其他文件中导入和使用它。
创建模块
首先,我们创建一个名为greetings.py
的模块,它包含一个名为print_hi
的函数:
1 | # greetings.py |
在这个模块中:
- 我们定义了一个名为
print_hi
的函数,它接受一个参数name
,并打印出问候语。 - 我们使用了一个特殊的条件语句
if __name__ == '__main__':
。当这个模块作为主程序运行时(即直接运行greetings.py
文件),这个条件语句下的代码会被执行。因此,它会打印出“Hi, PyCharm”。但是,当这个模块被其他文件导入时,这个条件语句下的代码不会被执行。
导入和使用模块
现在,我们可以在另一个Python文件中导入这个模块,并使用它提供的函数。例如,创建一个名为main.py
的文件:
1 | # main.py |
在这个文件中,我们使用import
语句导入了greetings
模块,并使用点符号(.
)访问模块中的print_hi
函数。当我们运行main.py
文件时,它会输出“Hi, Alice”。
注意,由于我们在greetings.py
文件中使用了if __name__ == '__main__':
语句,所以当我们导入这个模块时,它不会自动执行print_hi('PyCharm')
语句。因此,输出仅为“Hi, Alice”,而不包括“Hi, PyCharm”。
自定义Python包
什么是Python包
从物理结构上看,Python包就是一个文件夹,它包含一个__init__.py
文件,并且该文件夹内可以包含多个模块文件(即.py文件)。这个文件夹的层级结构可以表示包的层级关系。
从逻辑层面来看,包可以看作是一个更大规模的模块,它允许我们将相关的模块组织在一起,形成一个有层次的命名空间。
导入包
在Python中,导入包有几种不同的方式:
方式一:使用import语句
1 | import 包名.模块名 |
使用方式:
1 | 包名.模块名.目标函数() |
方式二:使用from…import语句
1 | from 包名 import 模块名 |
使用方式:
1 | 模块名.目标函数() |
方式三:直接导入目标函数
1 | from 包名.模块名 import 目标函数 |
使用方式:
1 | 目标函数() |
注意
- 在使用包中的模块或函数之前,需要确保包已经被正确安装或位于Python的搜索路径中。
__init__.py
文件是包的初始化文件,它可以是空的,也可以包含一些初始化代码或定义__all__
变量来指定当使用from 包名 import *
时应该导入哪些模块。
安装第三方包
什么是第三方包
第三方包指的是非Python官方提供的包,它们由Python社区中的开发者创建和维护。这些包通常用于解决特定的问题或提供特定的功能,例如数据处理、机器学习、网络编程等。
安装第三方包 - pip
pip是Python的包管理工具,它允许你轻松地安装、升级和卸载Python包。你可以使用pip来安装第三方包。
安装命令
在命令行中,使用以下命令来安装第三方包:
1 | pip install 包名称 |
这将会从Python Package Index(PyPI)下载并安装包。
pip的网络优化
由于pip默认连接的是国外的PyPI源,有时下载速度可能会很慢。你可以通过指定国内的镜像源来加速包的下载。例如,使用清华大学提供的PyPI镜像:
1 | pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名称 |
或者,你可以永久地修改pip的配置文件,将默认的源替换为国内的镜像源。这样,每次使用pip安装包时都会自动从国内的镜像源下载。
注意
- 在安装第三方包之前,确保你的Python环境已经正确设置,并且pip工具已经安装。
- 有些第三方包可能依赖于其他包或特定版本的Python,因此在安装之前最好查看包的文档以了解其依赖关系和要求。
- 如果你使用的是虚拟环境(virtualenv或conda等),则应在激活虚拟环境后安装第三方包,以确保它们仅在当前虚拟环境中可用。
定义自己的数据类型——类和对象
在Python中,类(Class)是一种抽象数据类型,它定义了包含数据(属性)和方法(函数)的对象的行为和状态。对象是类的实例,它具体地表示了类的属性和行为。
类的定义
类可以通过class
关键字来定义,类的名称通常以大写字母开头。类中可以定义属性和方法。
1 | class Cla: |
在这个例子中,Cla
是一个类,它定义了四个类属性a
、b
、c
和d
,它们都被初始化为None
。
封装
类中提供了私有成员的形式来支持。
- 私有成员变量
- 私有成员方法
定义私有成员的方式非常简单,只需要:
- 私有成员变量:变量名以
__
开头(2个下划线) - 私有成员方法:方法名以
__
开头(2个下划线)
即可完成私有成员的设置
对象的创建和属性赋值
要创建一个类的实例(对象),可以使用类名加上括号。然后可以通过点操作符.
来访问对象的属性或方法。
1 | c = Cla() # 创建一个Cla类的实例对象c |
打印对象c
会显示其内存地址,打印type(c)
会显示其类型,而打印c.a
则会显示其a
属性的值。
1 | print(c) # 输出对象c的内存地址 |
类的方法
类还可以定义方法,方法是类的函数,它可以在类的对象上执行操作。方法的第一个参数总是self
,它表示对象本身。
1 | class Man: |
在这个例子中,Man
类定义了两个方法:say_hi
和say_hi_with_msg
。这两个方法都接受self
作为第一个参数,表示对象本身。say_hi
方法打印出对象的name
属性,而say_hi_with_msg
方法则打印出对象的name
属性和一个额外的消息。
对象的方法调用
要调用对象的方法,可以使用点操作符.
和方法名。如果方法需要参数,可以在方法名后面的括号中提供。
1 | he = Man() # 创建一个Man类的实例对象he |
构造方法
在Python中,类的构造方法是__init__()
。当创建类的新实例时,这个方法会自动被调用。构造方法通常用于初始化新创建对象的属性。
示例
下面是一个简单的Student
类,它使用构造方法来初始化学生的姓名、年龄和电话号码。
1 | class Student: |
在这个例子中,当我们创建stu
对象时,__init__
方法被调用,并且我们传递的参数(”张三”, 31, “1145141919810”)被用来初始化对象的属性。
魔术方法(Magic Methods)
Python中的魔术方法,也称为特殊方法或双下划线方法,是以双下划线开头和结尾的方法。这些方法有特殊的意义,并且通常在某种特定的操作发生时由Python自动调用。
常见的魔术方法
__init__
: 构造方法,用于初始化新创建对象的状态。__str__
: 返回对象的字符串表示形式,当我们尝试打印对象或使用str()
转换对象时调用。__lt__
: 定义小于(<)操作符的行为。__le__
: 定义小于等于(<=)操作符的行为。__eq__
: 定义等于(==)操作符的行为。
示例
下面是一个扩展的Student
类,包含了__str__
,__lt__
,__le__
和__eq__
魔术方法的实现。
1 | class Student: |
输出:
1 | Student(name=张三, age=31, tel=1145141919810) |
注意,在实现比较魔术方法时,我们通常首先检查比较的对象是否也是相同类的实例。如果不是,我们可能会抛出一个TypeError
异常或者简单地返回False
(对于__eq__
方法)。在实现__lt__
和__le__
方法时,我们只比较了学生的年龄属性,但根据实际需要,可以比较更多的属性或应用更复杂的逻辑。
继承
在Python中,继承是面向对象编程的一个重要概念,允许我们创建一个类(称为子类或派生类)来继承另一个类(称为父类或基类)的属性和方法。这样,子类可以重用父类的代码,同时还可以添加或覆盖父类的功能。
单继承
单继承是指一个子类只继承一个父类的属性和方法。
1 | class Student: |
输出:1
5.0
多继承
多继承是指一个子类可以继承多个父类的属性和方法。在Python中,可以通过在类定义时,在括号内列出多个父类来实现多继承。
1 | class A: |
输出:1
2A method1
B method2
需要注意的是,多继承可能会引起方法解析顺序(MRO)的问题,Python中使用C3线性化算法来确定方法解析顺序。可以使用类名.mro()
或类名.__mro__
来查看类的MRO列表。
复写和调用父类成员
子类可以复写父类的成员属性和成员方法,即重新定义同名的属性或方法。当子类对象调用成员时,会调用复写后的新成员。如果需要使用被复写的父类成员,可以使用特殊的调用方式。
1 | class Student: |
输出:1
我是研究生张三,今年25岁,我的专业是计算机科学。
在上面的例子中,GraduateStudent
类复写了Student
类的introduce
方法,并在其中添加了专业信息。同时,在GraduateStudent
类的构造函数中,我们使用super().__init__(name, age)
来调用父类的构造函数初始化继承的属性。这样,我们就可以在子类中添加新的属性或方法,同时保留父类的功能。
访问父类成员
直接通过父类名调用
如果要直接通过父类名来调用其成员方法或访问成员变量,可以使用以下语法:
1 | 父类名.成员方法(self, 其他参数) |
这里需要注意的是,当直接调用父类的成员方法时,需要显式地将当前对象作为第一个参数传递(通常是self
)。
可以对实例化后的对象是用
使用super()
调用
super()
函数提供了一种动态的方式来访问父类的方法或属性,而不需要显式地引用父类的名字。这在多重继承的场景中特别有用,因为它可以确保正确地调用方法解析顺序(MRO)中的下一个类。
使用super()
调用父类成员的语法如下:
1 | super().成员方法(其他参数) |
注意,在使用super()
时,不需要显式地传递self
参数,因为super()
会自动处理。
在类定义的时候才可以使用
多态性
多态是面向对象编程的三大特性之一,它允许我们使用父类引用来指向子类对象,并且可以调用在子类中重写的方法。在Python中,多态的实现主要依赖于鸭子类型(duck typing)的概念,即不关注对象的实际类型,而是关注对象是否具有所需的方法。
下面我们通过一段代码来演示多态的概念:
1 | class Animal: # 定义一个Animal类作为父类 |
注意:在上述代码中,我们实际上并没有使用到a = Animal()
这个对象,因为Animal
类的speak
方法是一个空实现。如果我们尝试调用make_noise(a)
,它不会产生任何输出。在实际的多态示例中,我们通常会避免创建这样的空实现的父类对象。此外,虽然Robot
类没有继承自Animal
类,但由于它有一个与Animal
类中同名的speak
方法,我们仍然可以将其对象传递给make_noise
函数并调用其speak
方法。这就是鸭子类型的核心思想:不关注对象的实际类型,只关注对象是否具有所需的方法。然而,在严格的面向对象设计中,为了让代码更加清晰和可维护,我们通常会建议将具有相同行为(即具有相同方法)的类组织到一个继承体系中,并通过父类引用来操作子类对象。这样可以确保我们的代码更加符合面向对象的设计原则。在上述示例中,我们可以将Robot
类也设计为继承自Animal
类(如果逻辑上合理的话),这样就可以更加清晰地展示多态的特性。但是需要注意的是,并不是所有的具有相同方法的类都应该被组织到一个继承体系中。在实际开发中,我们需要根据具体的业务逻辑和设计需求来决定如何组织我们的类和对象。另外需要注意的是,Python中的多态与一些其他语言(如Java)中的多态略有不同。在Python中,由于动态类型和鸭子类型的特性,我们可以在不显式地声明接口或继承体系的情况下实现多态。这使得Python的代码更加灵活和简洁。但是在享受这种灵活性的同时,我们也需要注意保持代码的清晰性和可维护性。
变量的类型注解
在Python 3.5及以后的版本中,引入了类型注解(Type Annotations)的功能。类型注解允许开发者在代码中显式地标注变量、函数参数以及返回值的数据类型。这些注解主要用于帮助开发者编写更加清晰、易于理解的代码,并且为静态类型检查工具、集成开发环境(IDE)等第三方工具提供更好的支持。
类型注解的作用
- 代码提示:类型注解可以帮助IDE等开发工具提供更为准确的代码提示和自动补全功能。
- 静态类型检查:配合静态类型检查工具,可以在代码运行前发现潜在的类型错误。
- 文档化:类型注解也可以作为一种文档形式,帮助其他开发者理解代码中的数据类型。
变量的类型注解
变量的类型注解是在变量名后面加上冒号(:
)和类型名。需要注意的是,类型注解仅仅是注释,它不会改变Python的动态类型特性。也就是说,即使你标注了一个变量为整数类型,Python仍然允许你为这个变量赋值为其他类型。
1 | # 变量类型注解示例 |
然而,以下代码虽然类型注解为int
,但实际上赋值为字符串类型,Python不会报错,但在静态类型检查时会警告类型不匹配:
1 | var: int = "itheima" # 类型注解为int,但实际赋值为str,这不会引发运行时错误 |
函数的类型注解
函数的类型注解包括函数参数的类型注解和返回值类型的注解。参数的类型注解写在参数名后面,返回值类型的注解写在函数声明后面的箭头(->
)后面。
1 | # 函数类型注解示例 |
在这个例子中,greet
函数的参数name
被注解为字符串类型,返回值也被注解为字符串类型。
Union用法
当变量或函数参数可以是多种类型之一时,可以使用Union
来指定这些类型。Union
是从typing
模块中导入的。
1 | from typing import Union |
在这个例子中,my_var
被注解为可以是字符串或整数类型,而my_list
被注解为一个列表,其中的元素可以是字符串或整数类型。这样,在静态类型检查时,如果这些变量被赋予了不符合注解类型的值,工具就会发出警告。然而,在运行时,Python本身不会因为这些类型注解而引发错误。