# Python
- Python是解释型语言,使用它需要安装的 python 解释器(用于运行 python 程序),与编译型语言不同,要运行 python 程序并不需要把 python 代码编译成目标代码(机器码),而是在解释器上逐行执行。
- Python是跨平台的,它可以运行在 Windows、Mac 和各种 Linux/Unix 系统上。在 Windows 上写 Python 程序,放到 Linux 上也是能够运行的,这是因为Python 是一种解释型语言,只要有解释器就可以运行 python 代码,在Windows、Mac 和各种 Linux/Unix 系统上都可以安装 python解释器。
优点:
- 高级语言 使用时无需考虑内存管理之类的底层细节。
- 免费开源 你可以自由地阅读它的源代码、发布这个软件的拷贝、对它进行修改、把它的一部分用于自己的软件中。
- 可移植性 因为它是开源的,所以只需亿点点改动就能使它工作在不同平台上。现在 Python 已经被移植在许多平台上。
- 有丰富的库 许多功能不需要自己写,可以直接用别人写的库解决问题
- 可扩展性 如果你需要你的一段关键代码运行得更快或者希望某些算法不公开,你可以把你的部分程序用 C 或 C++ 编写,然后在你的 Python 程序中调用它们
缺点:
- 运行速度慢,非常消耗内存,为了提高速度,一般使用 C++ 写关键部分,然后用 Python 调用 C++
版本说明
目前 Python 有 Python2 和 Python3 两个版本,这两个版本不能相互兼容,该笔记的编写以 Python3 为准
Python 提供了将 Python2 转化为 Python3 的功能,这需要安装 2to3 ,在命令行工具中使用Python 3 的包管理器 pip 来安装
pip install 2to3
参考:2to3 的使用方法 (opens new window)
# 安装python
- 在 MacOS 上安装 Python:下载地址 (opens new window)
- 在 Windows 上安装 Python:下载地址 (opens new window)
# 输入和输出
# 输出
用 print()
可以向屏幕上输出指定的文字。例如输出hello, world
,用代码实现如下:
print('hello, world')
运行结果:
hello, world
输出变量值
一般输出一个变量只要需要把变量写入 print
函数中即可
x = 0
print(x)
但如果要和字符串一起输出,就需要用连接符 +
将字符串和变量连接起来
year = input()
month = input()
date = input()
print(year + "年" + month + "月"+ date +"日")
运行结果:
2024年9月22日
# 分隔符
当需要使用一个 print
函数输出多个数据时就要用到分隔符 ,
把这些数据分隔开
print("Hello", "world")
输出结果:
Hello world
由于是两个数据,输出结果会用空格将这两个数据隔开
如果想要将这个空格替换成其他符号 就要用到 sep
参数了
# 参数
- sep
该参数用于设置分隔多个输出项之间的分隔符,默认为一个空格
print("Hello", "world", sep="!")
输出结果:
Hello!world
- end
用于设置输出结束后的字符,默认为换行符 \n
print("Hello", "world", end="!")
输出结果:
Hello world!
print
可以同时使用多个参数,就像这样:
print("Hello", "world", sep="_", end="!")
其中 "Hello"
, "world"
, sep="_"
, end="!"
都是参数
技巧
end
参数用于定义 print
函数输出后的结尾工作,一般输出结束后会默认换行,如果要使 print
输出后不换行可以用 end=""
把换行符替换为空值
# 格式化输出
字符串格式化有多种方式
# 使用str.format()
方法
语法
"str".format()
用法
方法一:
name = "Alice"
age = 25
print("{} is {} years old.".format(name, age))
方法二:
name = "Alice"
age = 25
# 指定位置参数
print("{1} plays {0}".format("football", "Tom"))
方法三:
name = "Alice"
age = 25
# 关键字参数
print("{name} likes to play {game}".format(name="Jerry", game="chess"))
示例
示例一:
year = input()
month = input()
date = input()
print("{}年{}月{}日".format(year,month, date))
输入:
2024
9
22
输出:
2024年9月22日
示例二:
year = input()
month = input()
date = input()
#指定位置参数
print("{2}年{1}月{0}日".format(year,month, date))
输入:
2024
9
11
输出:
11年9月2024日
# 使用 f-string
非常推荐使用 f-string 进行格式化输出
- 输出时不需要考虑变量的数据类型,f-string 会将其他数据类型转换为适合输出的字符串类型
- 输出时用
{}
括住变量就行,不需要使用+
这样的连接符,不易出错且表达更直观 - 方便使用格式化指令,可以很快的实现保留小数点后几位之类的功能
- 性能相较于其他更加优异
f-string 是一种从 Python 3.6 开始引入的一种格式化字符串的方式,相较于 format 方法表达更加直观,性能更加优异。
使用时需要在字符串前加一个 f
,表示使用 f-string
进行字符串格式化,变量用 {变量名}
的形式表达
使用示例
name = "Alice"
age = 25
print(f"My name is {name} and I am {age} years old.")
输出:
My name is Alice and I am 25 years old.
使用 f-string 实现保留小数点后几位
pi= 3.141592653589793238462643383279 # 保留小数点后30位的 π 值
print(f"{pi:.2f}") # 输出保留小数点后两位的 π 值
f"{pi:.2f}"
中,字符串前的 f
表示使用 f-string 进行格式化输出,pi
是变量,:
表示使用格式化命令,.2
表示保留小数点后4位,随后的 f
表示这是一个浮点数
# 使用 string.Template 类
string.Template
的优势在于可以做一个字符串模板,使用时只需要替换这个模板中需要更改的部分
使用示例
from string import Template # 从 string 模块中导入 Template 类
# 设置变量
a = "Alice"
b = 25
t = Template("My name is $name and I am $age years old.")
# 输出结果
print(t.substitute(name=a, age=b))
输出:
My name is Alice and I am 25 years old.
# 使用占位符
示例
name = "Alice"
age = 25
print("My name is %s and I am %d years old." % (name, age))
输出:
My name is Alice and I am 25 years old.
代码中的 %s
和 %d
都是占位符,从 % (name, age)
中按照顺序依次替换占位符。
占位符会表达其所代替对象的数据类型,例如 %s
代表字符串类型 %d
十进制整数类型
更多内容参考 Python_printf-style String Formatting (opens new window)
# 字符串切片
字符串切片的基本语法是
<string>[<start>:<end>:<step>]
<start>
开始索引(默认为0)<end>
结束索引<step>
步长(默认为1)
输出第 5 个字符之前的所有字符
s = "Hello, world!"
print(s[:5])
输出:
Hello
输出第 6 到第 10 个字符
s = "Hello, world!"
print(s[5:10])
输出:
, wor
输出第 5 个字符之后的所有字符
s = "Hello, world!"
print(s[5:])
输出:
, world!
输出整个字符串
s = "Hello, world!"
print(s[:])
输出:
Hello, world!
从第一个字符开始,以步长为 2 依次输出
s = "abcdefgh"
print(s[::2])
输出:
aceg
步长就类似人类走路,步长越长跨过的字符越多,实际输出的字符就会变少,以上述为例,Hello, world!
从第一个字符 a
开始,由于步长为 2 ,所以每经过2个字符输出一次,所以第二次输出 c
,第三次输出 e
以此类推
# 多重切片
s = "abcdefghijklmn"
print(s[:5],s[5:10]) # 输出 abcde fghij
print(s[:5]+s[5:10]) # 输出 abcdefghij
# 反转字符串
步长为负时表示从后往前取值, -1
则表示从后往前逐个字符取值
s = "abcdefgh"
print(s[::-1])
输出:
hgfedcba
注意
::
并不是一个特殊的运算符,而是因为在语法 <string>[<start>:<end>:<step>]
中 这里的代码并没有设定 <start>
和<end>
所以变成了 : :<step>
,写紧凑点就成了 ::-1
# 转义符
当我们想要输出一些特殊符号例如 "
或者空格等因为语法原因导致内容无法被识别为要输出的字符串时就可以使用转义符 \
它可以将该符号转义为与语法不冲突的符号,成功以字符串的形式输出
在需要转义的符号前加上 \
即可,空格的转义符为 \n
# 输入
用 input()
可以向计算机输入数据,当计算机执行到 input()
代码时,计算机会等待用户进行输入,当用户输入完成后就会继续执行下一行代码
一般我们会设置一个变量用于保存计算机所输入的值,例如 x=input()
,当计算机执行到 x=input()
时,计算机会让用户进行输入,并把输入的内容赋值给变量 x
(这里的 =
表示赋值),这时 x
就等于刚才用户输入的值。
注意
默认情况下 input()
输入的内容会被存储为一个字符串类型的数据
x=input()
可以在 input()
括号中写一下提示性的话,来提示用户需要输入什么内容,例如:
name = input("请输入你的姓名:")
运行效果:
请输入你的姓名:
这时计算机就会输出 请输入你的姓名:
并等待用户的输入内容
# 数据类型
以下是 Python 的基本数据类型:
- 整数 (int):如
42
- 浮点数 (float):如
3.14
- 字符串 (str):如
"Hello"
(字符串类型的数据要用"
符号括起来) - 布尔值 (bool):如
True
和False
除此之外还有一些更加高级的容器类型:
- 列表(List):可变、有序,可以包含任意类型的元素
- 元组(Tuple):不可变、有序,可以包含任意类型的元素
- 集合(Set):无序、不重复,可变
- 字典(Dictionary):键值对形式,可变,无序
什么是容器类型?
容器可以存储多个元素,每个元素可以是任何类型的数据,所有的容器类型都具有可迭代性,说人话就是可以通过循环进行遍历,来访问容器中的每一个元素。
字符串不是容器类型!
字符串虽有容器类型的一些性质,例如支持切片和索引,但它并不是容器类型。因为字符串中的每个字符都只是单一的字符并不是独立的对象
# 列表
序列是一种存储有序数据的基本数据结构,它由多个元素或数据按照顺序排列而成。列表,元组,字符串都是序列
索引
# 创建列表
Python 中列表类型一般用 []
表示
list = []
这样就创建了一个空列表,列表中可以添加元素,这些元素用 ,
隔开
list = [1, 2, 3]
# 访问列表元素
一般用索引的方式来访问列表中的某个元素,索引一般从 0 开始,list[0]
表示索引列表第一个元素,list[1]
自然就是索引列表中的第二个元素了
a = list[0]
像这样就是索引列表中的第一个元素,并把它赋值给变量 a
示例:
list = [1, 2, 3]
a = list[0]
print(a)
输出结果
1
如果在索引值前加一个负号 -
表示从后往前索引,例如 list[-1]
就表示从后往前索引列表 list
示例:
list = [1, 2, 3]
a = list[-1]
print(a)
输出结果
3
# 访问列表中多个元素
Python 可以索引某个范围的多个元素,索引值之间要用 :
隔开,例如 list[1:4]
表示从第二个元素开始到第四个元素
list = [1, 2, 3, 4, 5]
a = list[1:4]
print(a)
输出结果
[2, 3, 4]
这样输出的是结果是带 []
的列表类型的数据,如果要输出这个列表中单一的值就要用到 解包(Unpacking)
list = [1, 2, 3, 4, 5]
a,b,c = list[1:4] # 使用解包赋值
print(a)
print(b)
print(c)
输出结果
2
3
4
- 访问列表中某个元素之后的所有元素
list = [1, 2, 3, 4, 5]
a = list[1:] # 访问索引值为 1 的元素及其之后的所有元素
print(a)
输出结果
[2, 3, 4, 5]
list[:1]
表示访问索引为 1 的元素前的所有元素,list[:-1]
表示访问从后往前数索引为 1 的元素之前的所有的元素
# 访问元素中的元素
若要索引的元素是字符串或容器元素,可以给通过二次或多次索引访问元素中的元素
访问列表中字符串中的字符
list = ["python", 2, 3,["a","b","c"], 4, 5]
a = list[0][1] # 访问的索引值为 0 的元素中索引值为 1 的字符
print(a) # 输出 y
访问列表中某容器中的元素
list = ["python", 2, 3,["a","b","c"], 4, 5]
a = list[3][0] # 访问的索引值为 3 的元素中索引值为 1 的元素
print(a) # 输出 a
# 修改列表
- 修改列表中的元素
修改列表 list
的第一个元素为 new value
list[0] = 'new value'
以下是用于测试效果的完整代码
list = [1, 2, 3, 4, 5]
list[0] = 'new value'
a = list[0]
print(a)
输出结果
new value
- 在列表中添加元素
这个方法可以在列表中添加新的元素,但添加的新元素会按照顺序依次排列,排在之前元素的后面
list.append('new item')
示例
list = [1, 3, 3, 3, 5]
list.append('new item')
print(list)
输出结果
[1, 3, 3, 3, 5, 'new item']
- 在列表中插入元素
前面的 append
方法只能在列表的后面添加元素,而 insert
方法可以在列表中的特定位置插入元素
例如这段代码 是在列表 list
中的第 4 个元素前插入元素 "x"
list.insert(3, "x")
示例
list = [1, 2, 3, 4, 5]
list.insert(3, "x")
print(list)
输出结果
[1, 2, 3, 'x', 4, 5]
- 删除元素
list.remove(3)
这个方法可以删除列表里对应的元素,例如这个例子是删除列表 list
中值为3的元素。但这个方法有个问题是只能删除一次,若列表里有多个 3 时,并不会删除所有的 3 而是从左往右遍历,当检测到 3 时删除这个元素,然后就结束了,之后的 3 就不管了,所以要删除一个列表中的所有 3 时就要使用使用 while 循环,遍历列表里的所有元素,并删除列表中的3,就像这样
list = [1, 3, 3, 3, 5]
while 3 in list:
list.remove(3)
print(list)
- 删除列表中指定位置的元素
例如这个例子是删除列表 list
中索引到的的第一个元素
del list[0]
- 清空列表
list.clear()
# 列表拼接
通过运算符 +
把列表 a
和列表 b
拼接起来
a = [1, 2, 3, 4, 5]
b = [6, 7, 8, 9, 10]
c = a + b
print(c)
输出结果
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
当然也可以这样(少使用一个变量)
a = [1, 2, 3, 4, 5]
b = [6, 7, 8, 9, 10]
a += b
print(a)
# 列表嵌套
a = [1, 2, 3, 4, 5]
b = [6, 7, 8, 9, 10]
c = [a, b]
print(c)
输出结果
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
# 列表比较
- 比较列表是否完全相等
if a == b:
- 比较列表内容是否相同(忽略顺序),思路是把列表转换成集合类型来比较
if set(a) == set(b):
- 比较列表的长度
if len(a) == len(b):
# 查看元素索引
index
方法可以帮助我们查看列表中某个元素的索引值
示例
list = [1, 2, 3, 4, 5]
a = list.index(4)
print(a)
输出结果
3
输出结果为 3 说明元素 4
的索引值为 3。这个方法也是一次性的,当列表中有多个相同的元素时它输出的索引值是第一个遍历到指定元素的索引值
如果要输出列表中所有的指定元素时,可以使用 enumerate
函数
list = [1, 2, 3, 3, 5]
indices = [i for i, value in enumerate(list) if value == 3]
print(indices)
输出结果
[2, 3]
# 获取列表长度
使用 len
函数可以获取数据的长度,它可以可以应用于多种数据类型,包括列表、元组、字符串、字典、集合等,这里以列表为例
list = [1, 2, 3, 3, 5]
length = len(list) # 获取列表长度
print(length)
输出结果
5
# 引用列表
copy()
方法用于复制列表,你也许会疑问,可以通过赋值的方式把一个变量的数据给另一个变量,为什么还需要copy()
来专门复制列表呢?
copy()
的复制与一般的赋值不同,赋值是在新的内存空间中再次存储相同的数据,而 copy()
像是指针一样,让新的变量指向原有的内存地址,不需要重新创建一个新的内存地址
注意
仅对可变类型的元素有效,若复制对象是不可变类型的元素时则与赋值一样,创建一个新的副本
a = [1, 2, 3]
b = a.copy()
print(b) # 输出: [1, 2, 3]
# 关于列表的函数&方法
函数
函数 | 说明 |
---|---|
len(list) | 列表元素个数,list 表示要计算元素个数的列表 |
max(list) | 返回列表元素最大值,list 表示要返回最大值的列表 |
min(list) | 返回列表元素最小值,list 表示要返回最小值的列表 |
list(seq) | 将元组转换为列表,seq 表示要转换为列表的元组或字符串 |
方法
方法 | 说明 |
---|---|
list.append(obj) | 在列表末尾添加新的对象,obj 为添加到列表末尾的对象 |
list.count(obj) | 统计某个元素在列表中出现的次数,obj 为列表中被统计的对象 |
list.extend(seq) | 在列表末尾一次性追加另一个序列中的多个值,seq 为追加的序列,例如列表、元组、集合、字典 |
list.index(obj) | 从列表中查找某个值第一个匹配项的索引位置,obj 为被查找的对象 |
list.insert(index, obj) | 将对象插入列表,index 表示要插入的位置的索引值,obj 要插入列表中的对象 |
list.remove(obj) | 移除列表中某个值的第一个匹配项,obj 是列表中要移除的对象 |
list.reverse() | 反转列表中的元素顺序 |
list.clear() | 清空列表 |
list.copy() | 引用列表 |
# 元组
- 元组是 Python 中的一种数据结构,用于存储多个元素。
- 元组中的元素是有序的,并且可以包含不同类型的元素(如整数、字符串、列表等)。
- 元组使用圆括号
()
来定义
空元组,表示没有元素的元组
a = ()
单元素元组(若元组中只有一个元素,则要在元素后加 ,
以便区分元组类型和普通括号)
a = = (10,)
多元素元组,一个元组包含存放多个不同类型的元素,各元素间用 ,
隔开
a = (1, 2, 3, 'a', 'b', 'c')
元组与列表的使用基本是一致的,例如访问,切片,解包等操作与列表都是相同的,列表可以使用的元组也可以。元组唯一与列表不同的是不可变性,列表元素是可以更改的,所以我们可以修改列表中的元素,但元组是不可以修改的。
- 元组通常用于表示固定的数据集合
- 列表用于表示可变的数据集合
# 集合
- 集合是一种无序且不重复的数据结构,用于存储多个元素。
- 集合中的元素是不能修改的,因为集合是无序的,无法用索引准确定位到某一个元素,所以切片,索引这一套在集合这里是不管用的
- 集合可以包含多种数据类型(如整数、浮点数、字符串、元组等)
# 创建集合
集合一般用 {}
表示
a = {1, 2, 3, 4, 5}
还有一种常见的表示方法
a = set([1, 2, 3, 4, 5])
这种方法本质上是通过 set
函数把一个列表转换成集合,这也是一种提取元素的好办法,可以方便的将列表表中重复的元素去除
a = set([1, 4, 2, 3, 4, 5, 3, 5])
print(a) # 输出: {1, 2, 3, 4, 5}
从代码的输出结果中我们可以看到,输出的结果去除了重复的元素,而且是按照某种顺序输出的。这是因为 Python 的集合内部使用哈希表来存储元素。哈希表的实现方式决定了元素的存储位置,哈希表中的编码顺序也许是按照某种顺序编排的,所以造成了集合中输出的元素貌似是按照某种顺序输出的假象。实际上集合中的元素排布并不是固定的,不应该依赖这种顺序
创建空集合
empty_set = set()
print(empty_set) # 输出: set()
若要创建一个空集合必须要使用 set
函数,而不是 a = {}
,因为这样创造出来的并不是一个空集合,而是一个空字典。字典和集合都用 {}
来表示,与集合不同的是,字典中的元素是以键值对的形式出现的
若在代码中给一个集合添加多个相同的元素是,集合存储时会去除这些重复的元素,所以你输出时并不会看到哪些重复的元素
a = {1, 2, 2, 3, 4, 4, 5}
print(a) # 输出: {1, 2, 3, 4, 5}
# 添加元素
使用 add 方法添加元素
a = {1, 2, 3}
a.add(4)
print(a) # 输出: {1, 2, 3, 4}
# 移除元素
移除元素有两种方法 remove(x)
和 discard(x)
,两者都可以移除元素。区别在于,若是移除的元素在集合中不存在时,使用 remove
会报错,而使用 discard
却不会
使用 remove
的方法移除不存在的元素
s = {1, 2, 3}
s.remove(4) # 移除元素 4
print(s) # 错误:KeyError: 4
使用 discard
方法移除不存在的元素
s = {1, 2, 3}
s.discard(4) # 移除元素 4
print(s) # 输出:{1, 2, 3}
# 集合的运算符
- 并集 (|)
set1 = {1, 2, 3}
set2 = {3, 4, 5}
union_set = set1 | set2
print(union_set) # 输出: {1, 2, 3, 4, 5}
- 交集 (&)
set1 = {1, 2, 3}
set2 = {3, 4, 5}
intersection_set = set1 & set2
print(intersection_set) # 输出: {3}
- 差集 (-)
set1 = {1, 2, 3}
set2 = {3, 4, 5}
difference_set = set1 - set2
print(difference_set) # 输出: {1, 2}
- 对称差集 (^)
set1 = {1, 2, 3}
set2 = {3, 4, 5}
symmetric_difference_set = set1 ^ set2
print(symmetric_difference_set) # 输出: {1, 2, 4, 5}
# 移除两个集合的交集
difference_update()
方法用于移除移除两个集合的交集,即两个集合都有的元素。这个方法是是更新原有的集合不是返回新的集合
# 创建两个集合
s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}
# 使用 difference_update()
s1.difference_update(s2)
print(s1) # 输出: {1, 2}
# 检查 s2 是否被修改
print(s2) # 输出: {3, 4, 5, 6}
# 检查两个集合是否有交集
isdisjoint()
`方法用于检查两个集合是否没有交集,即两个集合是否有共同的元素。- 如果两个集合没有共同的元素,
isdisjoint()
返回True
;否则返回False
。
# 创建两个集合
s1 = {1, 2, 3}
s2 = {4, 5, 6}
s3 = {3, 4, 5}
# 使用 isdisjoint()
result1 = s1.isdisjoint(s2)
print(result1) # 输出: True
result2 = s1.isdisjoint(s3)
print(result2) # 输出: False
# 检查一个集合是否是另一个集合的超集
issuperset()
方法用于检查一个集合是否是另一个集合的超集,即一个集合是否包含另一个集合的所有元素。若包含则返回 True
;否则返回 False
# 创建三个集合
s1 = {1, 2, 3, 4, 5}
s2 = {3, 4}
s3 = {6, 7}
# 使用 issuperset()
result1 = s1.issuperset(s2)
print(result1) # 输出: True
result2 = s1.issuperset(s3)
print(result2) # 输出: False
result3 = s2.issuperset(s1)
print(result3) # 输出: False
# 两个集合的对称差集
symmetric_difference()
方法用于返回两个集合的对称差集,也就是两集合交集的补集(全集为两集合的并集),即只在其中一个集合中出现的元素,但不在两个集合中同时出现的元素
# 创建两个集合
s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}
# 使用 symmetric_difference()
result = s1.symmetric_difference(s2)
print(result) # 输出: {1, 2, 5, 6}
这种方法实际上是创建了一个新的集合,用 symmetric_difference_update()
方法可以在原有集合上更新
# 创建两个集合
s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}
s1.symmetric_difference_update(s2)
print(s1) # 输出: {1, 2, 5, 6}
# 关于集合的方法
方法 | 说明 |
---|---|
add() | 添加元素,仅用于添加单个元素 |
update() | 添加元素,可添加多个元素,可以接受一个迭代对象 |
clear() | 清空集合中的元素 |
copy() | 复制集合,不是创建新的集合,而是让新的变量指向该集合 |
difference() | 返回多个集合的差集 |
discard() | 删除集合中指定的元素,当元素不存在时不会报错 |
remove() | 删除集合中指定的元素,当元素不存在时会报错 |
pop() | 随机移除元素 |
isdisjoint() | 判断两个集合是否有交集,若有返回 False 若无返回 True |
issuperset() | 检查一个集合是否是另一个集合的超集,若是则返回 True ,否则返回 False |
union() | 返回两个集合的并集 |
len() | 返回集合元素个数 |
symmetric_difference() | 返回两个集合的对称差集 |
注意
difference()
,intersection()
,symmetric_difference()
这三个函数会返回处理好的集合,若是在函数名后加上 _update()
则是把处理好的集合更新在原来的集合上,不返回新的集合
# 字典
- 字典是一种可变的键值对数据结构,常用于数据查找和更新
- 字典中的键是不可变的,值是可变的,它们可以是任何数据类型(如整数、浮点数、字符串、元组等)
- 字典使用
{}
来定义,键值对之间用冒号:
分隔,每对键值对之间用逗,
分隔
注意
在 Python 3.7 之前,字典(dict)是无序的,也就是说,当你访问字典的键或值时,它们的顺序可能是随机的,不保证按照插入顺序排列。然而,从 Python 3.7 开始,字典开始保持插入顺序,这意味着元素会按照插入的顺序进行排序。
创建字典
- 使用
{}
创建字典,这是最基本的字典表示方式
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
- 使用
dict()
函数创建字典
a = dict(name='Alice', age=25, city='New York')
- 使用键值对列表创建字典
a = dict([('name', 'Alice'), ('age', 25), ('city', 'New York')])
访问字典
- 通过键访问字典中的值
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
print(a['name']) # 输出: Alice
- 使用
get
方法访问字典中的值
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
x = a.get('name')
print(x) # 输出: Alice
get
方法还有一个值,用于设置当键不存在时返回的内容
a = {"name": "Alice", "age": 25, "city": "New York"}
x = a.get("gender", "Unknown")
print(x) # 输出: Unknown
修改字典
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
a['age'] = 18 # age 的值
print(a) # 输出: {'name': 'Alice', 'age': 18, 'city': 'New York'}
也可以通过这种方式给字典添加元素
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
a['gender'] = 'Female' # 添加新键值对
print(a) # 输出: {'name': 'Alice', 'age': 25, 'city': 'New York', 'gender': 'Female'}
删除字典
- 使用
del
关键字删除键值对
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
del a['age']
print(a) # 输出: {'name': 'Alice', 'city': 'New York'}
- 使用 pop() 方法删除键值
与 del
不同的是 pop()
是一个方法,它在执行删除操作的同时还可以返回被删除的值
a = {"name": "Alice", "age": 25, "city": "New York"}
b = a.pop("age")
print(b) # 输出: 25
print(a) # 输出: {'name': 'Alice', 'city': 'New York'}
- 使用
clear()
方法清空字典
a = {"name": "Alice", "age": 25, "city": "New York"}
a.clear()
print(a) # 输出: {}
# 字典常用方法
方法 | 说明 |
---|---|
keys() | 获取字典的键 |
values() | 获取字典的值 |
items() | 获取字典的键值对 |
- 获取所有键
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
keys = a.keys()
print(keys) # 输出: dict_keys(['name', 'age', 'city'])
- 获取所有值
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
values = a.values()
print(values) # 输出: dict_values(['Alice', 25, 'New York'])
- 获取所有键值对
a = {'name': 'Alice', 'age': 25, 'city': 'New York'}
items = a.items()
print(items) # 输出: dict_items([('name', 'Alice'), ('age', 25), ('city', 'New York')])
字典的遍历
a = {"name": "Alice", "age": 25, "city": "New York"}
for key in a:
print(key) # 输出: name, age, city
如果用 for
循环直接遍历字典,得到的只有字典里的键,若要遍历字典里的值可以把迭代对象改为 a.values()
,若要遍历键值对就把迭代对象改为 a.items()
# 转换数据类型
int()
将其他数据类型转换为整数float()
将其他数据类型转换为浮点数str()
将其他数据类型转换为字符串bool()
将其他数据类型转换为布尔值list()
将其他数据类型转换为列表tuple()
将其他数据类型转换为元组dict()
将其他数据类型转换为字典set()
将其他数据类型转换为集合eval()
可以将字符串动态转化为其他数据类型,例如当数据需要作为浮点数进行计算时,它就会将该字符串转化为字符串类型的数据
提示
当你需要转换数据类型,但又不确定将数据转换成什么类型时就可以使用eval()
,他会自动将数据转换为合适的类型
# int()
将字符串转换为整数
num_str = "123"
num_int = int(num_str)
print(num_int)
输出:
123
将浮点数转换为整数
num_float = 123.45
num_isnt = int(num_float)
print(num_isnt)
输出:
123
提示
用 int
将浮点数转换为整数是直接取浮点数的整数部分,若要四舍五入建议使用 round
函数
# float()
将字符串转换为浮点数
num_str = "123.45"
num_float = float(num_str)
print(num_float)
输出:
123.45
将整数转换为浮点数
num_int = 123
num_float = float(num_int)
print(num_float)
输出:
123.0
# str()
将整数转换为字符串
num_int = 123
num_str = str(num_int)
print(num_str)
输出:
123
注意
虽然输出的还是 123
但是经过 str()
函数的处理后,数据类型已经从整数类型变为了字符串类型,这时的 123
并不能像整数一样进行算数运算
将浮点数转换为字符串
num_float = 123.45
num_str = str(num_float) # 结果: "123.45"
# bool()
# 将整数转换为布尔值
num_int = 0
num_bool = bool(num_int) # 结果: False
num_int = 1
num_bool = bool(num_int) # 结果: True
# 将字符串转换为布尔值
num_str = ""
num_bool = bool(num_str) # 结果: False
num_str = "hello"
num_bool = bool(num_str) # 结果: True
大部分编程语言中非零的值被视为真值(True)如下:
当把整数 5
转换为布尔类型后输出的值是 True
num_int = 5
num_bool = bool(num_int)
print(num_bool)
输出:
True
这里如果把 5
换作 0
就会输出 False
# list()
将字符串转换为列表
str_data = "hello"
list_data = list(str_data)
print(list_data)
输出:
['h', 'e', 'l', 'l', 'o']
将元组转换为列表
tuple_data = (1, 2, 3)
list_data = list(tuple_data)
print(list_data)
输出:
[1, 2, 3]
# tuple()
将列表转换为元组
list_data = [1, 2, 3]
tuple_data = tuple(list_data)
print(tuple_data)
输出:
(1, 2, 3)
将字符串转换为元组
str_data = "hello"
tuple_data = tuple(str_data)
print(tuple_data)
输出:
('h', 'e', 'l', 'l', 'o')
# dict()
# 将列表转换为字典
list_data = [("a", 1), ("b", 2)]
dict_data = dict(list_data) # 结果: {'a': 1, 'b': 2}
# 使用关键字参数创建字典
dict_data = dict(a=1, b=2) # 结果: {'a': 1, 'b': 2}
# set()
# 将列表转换为集合
list_data = [1, 2, 2, 3, 4]
set_data = set(list_data) # 结果: {1, 2, 3, 4}
# 将字符串转换为集合
str_data = "hello"
set_data = set(str_data) # 结果: {'h', 'e', 'l', 'o'}
# 浮点数误差处理
当我们在Python中执行 print(0.1 + 0.2)
时会输出什么呢?0.3?实际上输出的结果是 0.30000000000000004
,为什么小数最后一位会出现 4 呢?之所以产生这种误差与浮点数在计算机中的存储方式有关。
任何数据在计算机都是以二进制形式表示的,浮点数也不例外,在计算机中一个浮点数由符号位,指数,尾数三部分表示。
- 符号位用来表示正负
- 指数表示浮点数用科学计数法表示时的幂次
- 尾数表示科学计数法中的有效数字,就像这样
符号位 指数 尾数
1 01001111 11010000000101111111011
这样的表示方式有天然的缺陷,浮点数的尾数位是有限制的,当超过存储范围时浮点数就会被截断,从而导致浮点数失去精度。就拿 0.1+0.2
为例,0.1
在二进制中是一个无限循环小数:0.00011001100110011...
被截断后再转化为十进制时为0.1000000000000000055511151231257827021181583404541015625
,
0.2
在二进制中也是一个无限循环小数:0.0011001100110011...
同样截断后转化成十进制为 0.200000000000000011102230246251565404236316680908203125
,所以当用计算机直接计算 0.1+0.2
时结果近似为0.30000000000000004
那如何避免这种误差呢?
可以把浮点数先转换成整数进行计算,计算后的结果再转换回浮点数
在 Python 中可以使用标准库中的 Decimal
来进行高精度的十进制浮点数的运算,避免误差
from decimal import Decimal
a = Decimal('0.1')
b = Decimal('0.2')
result = a + b
print(result) # 输出: 0.3
在编写程序是直接用等号对比两浮点数是否相等的方法并不可靠(0.1==0.1
),应该计算这两个数的差是否小于某个误差的范围
a = 0.1+0.2
b = 0.3
abs(a-b<1e-6)
在Python中也内置了判断浮点数是否相等的函数 isclose
from math import isclose
x = isclose(0.1 + 0.2,0.3)
print(x)
# 字符串的替换
在 Python 中,字符串是不可变对象,这意味着你不能直接修改字符串中的某个字符。
虽然字符串不能修改但列表可以,所以可以先把字符串转换成列表后修改,修改完成后再转换为字符串
s = "hello"
temp_list = list(s)# 将字符串 s 转换为列表 temp_list
temp_list[1] = 'a'# 修改列表中的第二个元素(索引为1)为 'a'
b = ''.join(temp_list)# 使用 join 方法将列表 temp_list 转换回字符串 b
print(b) # 输出: hallo
也可以把字符串切片拆开再整合
s = "hello"
b = s[:1] + 'a' + s[2:]
print(b) # 输出: hallo
创建一个新的字符串 b,将 s 中的第一个字符和第二个字符后的所有字符,切片提取,将字符 a 放入两段切片中间并将字符串连接起来
使用字符串的 replace
方法
s = "hello"
b = s.replace('e', 'a') # 将字符串中的 e 替换为 a
print(b) # 输出: hallo
# 多行字符串
Python 代码中,字符串都是在一行表示,如果要换行需要用换行符 \n
这并不能很直观的反映我们要输出的内容这时就可以使用 """
或 '''
来表示要输出的字符串内容,这种方式不会消除换行符,保留了字符串内容原有的格式
Yoseya = """\
*** *** ********* ****** ******** *** ** ***
*** *** **** **** *** ** *** ** ** **
*** *** *** *** *** ** *** ** ** **
*** *** *** ****** ******** *** ** **
*** *** *** *** ** *** ***********
*** **** **** *** ** *** ** **
*** ******** ****** ******** *** ** **\
"""
print(Yoseya)
输出结果
*** *** ********* ****** ******** *** ** ***
*** *** **** **** *** ** *** ** ** **
*** *** *** *** *** ** *** ** ** **
*** *** *** ****** ******** *** ** **
*** *** *** *** ** *** ***********
*** **** **** *** ** *** ** **
*** ******** ****** ******** *** ** **
这是通过三引号字符串的方式,用 *
拼凑的 YOSEYA
,(代码中的 \
是为了去除首尾看不见的换行符)
# 注释
注释一般用于解释代码的作用,并不会执行
# 这是一个单行注释,用于对此行代码进行说明
# 声明
注释除了以上用法外,还有另一种特殊的用法。一般注释是不会执行的,除了代码开头的两行特殊注释,以下代码就是开头的前两行注释,第一行叫做(Shebang Line)用于指定执行代码的解释器,可以用它来指定所安装的不同版本的 Python 解释器来执行该文件中的代码,第二行用于指定代码所用的字符编码格式,Python 一般默认使用 UTF-8,它们的使用一般在 Linux 和 macOS 上比较常见
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#!/
表示这是一个可执行脚本文件,后面跟着的是解释器的路径。例如 /usr/bin/python3
,env
可以帮助找到正确的解释器路径
# 多行注释
Python 中并不直接支持多行注释,但可以通过其他方式实现多行注释的效果,例如要用 """
或 '''
括起来表示,这种方式原本是用于创建多行字符串的,但创建出来的字符串除了会占用内存外,不会对程序造成其他的影响。所以可以当作注释使用
"""
这是一个多行注释
可以跨越多行
"""
注意
这段注释是一堆字符串,但由于没有设置变量,所以它虽然占用内存,但没有办法直接在内存中找到它,使用它。
# 变量
设置变量的过程其实是向计算机申请内存空间的过程,给变量赋的值会存储在计算机的内存中,当使用这个变量时计算机就会从内存里找到这个变量的值
- 变量的首字符不能是数字
- 变量名中间不能出现空格(空格用
_
代替) - 变量名只能包含字母、数字和下划线 _(理论上可以使用中文作为变量名,但不建议)
- 变量名区分大小写,例如 x 和 X 是不同的变量
- 建议使用有意义的变量名,以便代码更具可读性
- 不建议使用中文作为变量名
- 不要将 Python 关键词(保留字)作为变量名 查看指定字符是否为关键词 (opens new window)
示例
设置一个变量 x
并给这个 x
赋值为 0
x = 0
# 变量赋值
给变量赋值不同类型的数据
x = 10 #整数类型
pi = 3.14159 #浮点数类型
name = "Alice" #字符串类型
# 变量的作用域
全局变量:
写在公共部分的变量,并不属于某个函数,全局变量可以在程序中的任何地方使用
x = 10
def function():
print(x) # 输出 10
function()
print(x) # 输出 10
这段代码会输出两个 10
,说明在函数内和函数外都可以使用这个全局变量 x
局部变量:
在函数内部定义的变量,只在该函数内部有效
def function():
x = 10
print(x) # 输出 10
function()
print(x) # 报错:NameError: name 'x' is not defined
这段代码会输出一个 10
并报错,这是因为最后一行代码的print()
无法获取x
的值,因为变量 x
是写在
# 重新赋值
x = 10
x = 20
print(x) # 输出 20
输出结果:
20
代码逐行执行,第二行代码覆盖了第一行,所以输出的是第二次赋的值
# 多变量赋值
一次性给变量 a, b, c
分别赋值 1, 2, 3
a, b, c = 1, 2, 3
print(a, b, c) # 输出 1 2 3
输出结果:
1 2 3
# 变量交换
通过多变量赋值的方法可以将两个变量的值进行互换
x=1
y=0
x,y=y,x #交换两个变量的值
print(x,y)
输出结果:
0 1
# 将多个变量同时赋相同的值
x=y=z=1
print(x,y,z)
输出结果:
1 1 1
# 运算符
Python 语言支持以下类型的运算符:
算术运算符 ,比较运算符 ,赋值运算符 ,逻辑运算符 ,位运算符 ,成员运算符 ,身份运算符
# 算术运算符
运算符 | 说明 | 实例 |
---|---|---|
+ | 加法运算(返回两数之和) | 1 + 2 返回3 |
- | 减法运算(返回两级之差) | 3 - 2 返回1 |
* | 乘法运算(返回两数之积) | 2 * 3 返回6 |
/ | 除法运算(返回两数之比) | 2 / 6 返回3 |
** | 幂运算(返回该数的n次方) | 2 ** 3 返回8 |
% | 模运算(返回除法的余数部分) | 10 % 3 返回1 |
// | 整除(返回除法的整数部分) | 10 // 3 返回3 |
注意
//
是往数值小的方向取整数,例如-10 // 3
返回-4
使用示例:
# 输出运算结果 x
x = 1 + 2
print(x) # 输出结果3
# 运算并直接输出
print(2 * 3) # 输出结果6
# 比较运算符
运算符 | 说明 | 示例 |
---|---|---|
== | 等于(若两数相等则返回 True 否则返回 False ) | a == b |
!= | 不等于(若两数不相等则返回 True 否则返回 False ) | a != b |
> | 小于(若 a 大于 b 则返回 True 否则返回 False ) | a > b |
< | 大于(若 a 小于 b 则返回 True 否则返回 False ) | a < b |
<= | 小于等于(若 a 小于或等于 b 则返回 True 否则返回 False ) | a <= b |
>= | 大于等于(若 a 大于或等于 b 则返回 True 否则返回 False ) | a >= b |
比较运算符常用于条件判断(if
语句)或者循环条件(while
和 for
)
使用示例
示例1:
x = 3
print(x == 3)
输出:
True
示例2:
age = 18
if age >= 18:
print("成年人")
else:
print("未成年人")
输出:
成年人
示例3:
i = 0
while i < 5:
print(i)
i += 1
输出:
0
1
2
3
4
# 赋值运算符
运算符 | 说明 | 示例 |
---|---|---|
= | 赋值 | c = a + b 将 a + 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 |
使用示例
c = 2
c += 1 # 相当于c=c+1
print(c)
输出:
3
# 逻辑运算符
运算符 | 说明 | 示例 |
---|---|---|
and | 与 | 两个操作数的值都为 True (真),则结果为 True (真);否则为 False (假) |
or | 或 | 至少有一个操作数为 True (真),则结果为 True (真);否则为 False (假) |
not | 非 | 对操作数的布尔值取反,若原值为 True (真)则结果为 False (假),若原值为 False (假)则结果为 True (真) |
逻辑运算符常用于条件判断(if
语句)或者循环条件(while
和 for
)
# 位运算
运算符 | 说明 | 示例 |
---|---|---|
& | 与(位运算) | (a & b )两个对应的位都为 1 ,则该位的结果为 1 ,否则为 0 |
| | 或(位运算) | (a | b )对应的二个位有一个为 1 时,结果位就为 1 |
^ | 异或 | (a ^ b )两个对应的位不同时为 1 ,否则为 0 |
~ | 取反 | (~a ) 把 1 变为 0 ,把 0 变为 1 |
<< | 左移 | (a << 2 )二进制位整体向左移动(高位丢弃,低位补0) |
>> | 右移 | (a >> 2 )二进制位整体向右移动(高位丢弃,低位补0) |
示例
----
分割线上是 a
,b
以及它们对应的值,分割线下是经过不同位运算后的结果
a 0011 1100
b 0000 1101
---------------------
a&b 0000 1100
a|b 0011 1101
a^b 0011 0001
~a 1100 0011
a<<2 1111 0000
a>>2 0000 1111
# 成员运算符
成员运算符用于检查序列中是否包含某个特定的元素
运算符 | 说明 |
---|---|
in | 若序列中包含该元素则返回 True ,否则返回 False |
not in | 若序列中不包含该元素则返回 True ,否则返回 False |
使用示例
# 判断元素是否在列表中
list = [1, 2, 3, 4, 5]
if 3 in list:
print("3 在列表中")
# 判断元素是否不在字串中
str = "Hello, world!"
if "x" not in str:
print("'x' 不在字符串中")
# 身份运算符
身份运算符用于比较两个对象的是否是同一个对象,即具有相同的内存地址
运算符 | 说明 | 示例 |
---|---|---|
is | 两个对象的内存地址相同则返回 True ,否则返回 False | a is b |
is not | 两个对象的内存地址不同则返回 True ,否则返回 False | a is not b |
# 优先级
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
() | ** **= | +x -x ~x | * / // % | + - | << >> | & | ^ | | | == != < <= > >= | not | and | or |
提示
括号()
可以用来改变表达式中运算符的优先级,例如2 + 3 * 4
和(2 + 3) * 4
,前者优先运算3*4
,而后者优先运算2+3
# 层级关系
提示
在编写 Python 时,一般用 4 个空格表示一次缩进
在 Python 中通过缩进来表达层级关系,以下面的代码为例
age = 17
if age >= 18:
print("abc")
print("123")
这段代码中使用了一个条件语句,当满足条件时就会执行之后的代码,如果条件不满足就会跳过后面这段代码,很明显条件中需要 age
大于等于 18 ,所以条件并不满足。代码中有两个 print
函数,print("abc")
有缩进,所以属于 if
语句, print("123")
没有缩进,与 if
层级并列(不属于 if
语句)
输出结果:
123
print("abc")
属于 if
语句,所以当条件满足时就会执行该代码,如果条件不满足则不执行,由于该程序条件不满足,所以这里并不能输出 abc
,而 print("123")
并不属于 if
语句,所以不受 if
条件的影响 ,可以直接输出 123
。
def compare(a, b):
if a > b:
return a
else:
return b
print(compare(4, 5))
这段代码中 def compare(a, b):
和 print(compare(4, 5))
是第一层级,
if a > b
和 else
是第二层级,return a
和 return b
第三层级,层级间是包含关系,第一层级包含第二层级,第二层级包含第三层级
# 条件语句
条件语句用关键词 if
表示,if
后面是需要进行判断的条件,当满足条件时就执行下一行,如果不满足条件则跳过(这里的跳过并不是跳过下一行,而是跳出 if
语句,进入和 if
语句并列的层级,如果 if
语句中有多行代码,都会一并跳过,不会执行)
if age >= 18:
print("yes")
这是一个 if
语句,age >= 18
是它的条件,print("yes")
是条件满足后执行的代码(必须用缩进表示它的所属于 if
语句)
前面只说了满足条件时执行的情况,可以用 else
编写在条件不满足时所要执行的代码
if age >= 18:
print("yes")
else:
print("no")
这段代码的意思是,如果变量 age
的值大于等于 18 则输出 yes
,否则输出 no
# 多条件语句
如果要进行筛选,就需要用到多条件语句 elif
,当第一个 if
条件不成立时,程序会继续检查 elif
后面的条件,直到找到一个条件满足的情况。例如
if score > 90:
print("A")
elif score > 80:
print("B")
elif score > 60:
print("C")
else:
print("D")
这里假设 score = 75
,执行程序后检查 score
是否大于 90,条件不满足则继续检查 score
是否大于 80,条件也不满足,继续检查 score
是否大于 60,条件满足,则输出 C
# 并列条件语句
现在需要实现一个程序,输入月份,输出这个月有多少天。如何实现这个程序? 1、3、5、7、8、10、12 月有 31 天;4、6、9、11 月有 30 天。只需要判断月份再输出对应的天数就行了,通常我们会想到用语句嵌套来一个月一个月判断
# 获取用户输入的月份
month = int(input("请输入月份(1-12):"))
# 判断月份并输出对应的天数
if month == 1:
print(f"{month}月有31天")
else:
if month == 2:
print(f"{month}月有28天或29天(闰年时为29天)")
else:
if month == 3:
print(f"{month}月有31天")
else:
if month == 4:
print(f"{month}月有30天")
else:
if month == 5:
print(f"{month}月有31天")
else:
if month == 6:
print(f"{month}月有30天")
else:
if month == 7:
print(f"{month}月有31天")
else:
if month == 8:
print(f"{month}月有31天")
else:
if month == 9:
print(f"{month}月有30天")
else:
if month == 10:
print(f"{month}月有31天")
else:
if month == 11:
print(f"{month}月有30天")
else:
if month == 12:
print(f"{month}月有31天")
else:
print("输入的月份无效,请输入1到12之间的数字")
的确这种方法可以实现,但这样的代码存在几个缺点:
- 代码冗长难以阅读和维护。
- 扩展性差,如需增加新的条件或者修改现有条件,需要手动添加或修改多个 if-else 语句,容易出错。
- 性能下降,复杂的条件判断中,嵌套的 if-else 语句可能会导致性能下降。
为了解决这些问题,我们可以使用逻辑运算符帮忙
# 获取用户输入的月份
month = int(input("请输入月份(1-12):"))
# 判断月份并输出对应的天数
if month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12:
print(f"{month}月有31天")
elif month == 4 or month == 6 or month == 9 or month == 11:
print(f"{month}月有30天")
elif month == 2:
print(f"{month}月有28天或29天(闰年时为29天)")
else:
print("输入的月份无效,请输入1到12之间的数字")
这样一来代码就精简了许多,但我还是不满意,这个判断条件也太长了吧,这是我就想到了另一种方法来替代这些流水线式的判断条件,可以使用容器!我们可以把这些月份放在容器里,让 if
检查这个容器中的月份,根据月份来输出天数
if m in [1, 3, 5, 7, 8, 10, 12]:
print("31")
elif m in [4,6,9,11]:
print("30")
elif m == 2:
print("28 or 29")
这里我使用列表作为容器,也可以使用字典等其他容器类型
再举一个例子,比如判断闰年,闰年分以下两种
- 普通闰年:年份是 4 的倍数,且不是 100 的倍数
- 世纪闰年:年份是 400 的倍数
要同时满足以上两种情况可以把 and
和 or
搭配使用
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
return True
return False
# 语句嵌套
Python 支持语句的嵌套,就是可以把一个语句结构放在另一个语句结构之中。例如下面这段代码,在一个条件语句里嵌套了另一个条件语句,当条件 1 满足时就会执行里面的判断语句,判断条件 2 是否满足,如果条件 1 不满足就会进入执行 else:
语句后的代码
if condition1:
# 条件1成立时执行的代码
if condition2:
# 条件2成立时执行的代码
else:
# 条件2不成立时执行的代码
else:
# 条件1不成立时执行的代码
# 条件表达式
条件表达式(也称为三元运算符)是一种简洁的方式来编写条件逻辑
语法
value_if_true if condition else value_if_false
condition
:一个布尔表达式,用于判断条件是否成立。value_if_true
:如果表达式成立(True
)则返回这个值。value_if_false
:如果表达式不成立(False
)则返回这个值。
例如,这段代码表示 如果 x > y
成立则返回 x
否则返回 y
x if x > y else y
也可以嵌套使用
a if a > b and a > c else (b if b > c else c)
先判断 a
是否大于 b
和 c
,若成立则返回 a
否则继续判断 b
是否大于 c
若成立则返回 b
否则 返回 c
# 循环语句
- Python 提供了两种循环语句,分别是
for
循环和while
循环 - 当循环次数确定时使用
for
,循环次数不确定时用while
for
主要用于迭代,while
主要根据条件进行循环
# while
while 循环语句会根据条件进行循环,如果条件满足则结束循环,条件不满足则继续循环,直至满足条件
a=0
while a < 5:
print(a)
a+=1
输出结果
0
1
2
3
4
这段代码有一个 while
循环语句,while
后面是判断的条件,如果条件满足就跳出 while
语句,如果条件不满足就执行 while
语句中的代码,执行完后在回到 while
所在的那行代码重新判断条件是否满足,如果不满足则继续,直到满足为止
# for
for
循环语句常用于遍历对象中的元素
使用 for
循环语句遍历字符串
word = "yoseya"
for x in word:
print(x)
也可以这样
for x in "yoseya":
print(x)
输出结果
y
o
s
e
y
a
这段代码中的 x
是循环变量,跟在 in
后面的是要进行遍历的对象,这个对象可以是变量,也可以是字典,元组,列表,字符串这样类型的数据(它们都有一个共同的特点:一个对象包含多个元素。所以它们具有可迭代性)
提示
x
是一个临时申请的变量,用于存储当前迭代中的元素,在每次迭代后,x
的值会被更新为下一个元素
# 循环终止
for
循环是怎么知道自己应该什么时候结束循环呢?
答案是,通过异常。
例如下面这段代码会输出 1~9,为什么到 10 就不输出了呢?因为 range
只生成一个 1~9 的序列,到 10 时就没有输出的东西了,于是就会出现异常导致 for
循环终止
for i in range(10):
print(i)
我们可以通过制造异常让for循环提前终止
for i in range(10):
if i == 5:
raise ValueError("这里制造一个异常")
print(i)
输出结果
0
1
2
3
4
Traceback (most recent call last):
File "xxx\test.py", line 3, in <module>
raise ValueError("这里制造一个 异常")
ValueError: 这里制造一个异常
以上只是讲解 for
循环终止的原理,如果想要提前终止循环还是要使用 break
# break
break
语句用于提前终止循环
for i in range(10):
if i == 5:
break
print(i)
解析:range
函数可以从 0 开始生成一个整数序列,例如 range(10)
就是生成序列 1,2,3,4,5,6,7,8,9,10
,for 循环语句会按照这个序列依次给变量 i
赋值,for
语句中嵌套到了一个 if
判断语句,当变量 i
等于 5 时进入 if
语句,随后执行 break
语句,跳出 for
循环语句
输出结果
0
1
2
3
4
由于在变量 i
等于 5 时就执行 break
语句 跳出了循环,所以就不会再输出变量 i
的值了
# continue
continue
语句用于跳过当前循环的剩余部分,继续执行下一次循环,与break
语句不同的是 continue
语句不会跳出循环,而是跳过 continue
语句之后的代码,继续进行循环。通过这个语句可以实现一个对于奇偶数的筛选,如下
for i in range(10):
if i % 2 == 0:
continue
print(i)
解析:range
函数生成了序列 1,2,3,4,5,6,7,8,9,10
for
循环语句按照序列依次给变量 i
赋值,当变量 i
被2整除时进入 if
执行 continue
语句,跳过之后的代码(for循环语句内)继续进行下一次循环
输出结果
1
3
5
7
9
参考:如何判断奇偶数?
# else
for
循环中的 else
语句会在循环正常结束(未被 break 终止)时执行
for i in range(10):
if i == 5:
break
print(i)
else:
print("循环正常结束")
这段代码中 break
会正常执行所以不会执行 else
语句中的代码,我们可以创造一个情况让 break
不执行,例如把 if i == 5:
改为 if i == 11:
,由于 变量 i
永远不可能为11,所以 break
语句永远不会执行,这时再试试结果会不会输出 循环正常结束
# 函数
函数是什么?
函数是一堆被封装起来的代码。当我们需要实现一个功能,这个功能在之后不同的场景中可能会多次用到,为了避免重复编写这一功能,所以我们把实现这个功能的代码封装起来,当再用到时就可以用语句调用这段代码,不用重复编写
函数的优点
- 代码复用:通过定义函数,可以在程序的不同部分多次调用它,避免重复编写相同的代码。
- 模块化:函数使得程序结构更加清晰,易于理解和维护。
- 易于调试:函数将程序分解成小的独立部分,便于定位和修复错误。
- 封装性:函数内部的具体实现细节对外部是隐藏的,只暴露必要的接口
定义函数
函数使用关键词 def
定义,后面跟着函数名和参数,参数写在括号 ()
里
# 定义函数
def greet(name):
print(f"Hello, {name}!")
# 调用函数
greet("yoseya")
这段代码中 greet
是函数名,name
是参数,参数可以是一个也可以是多个,多个参数间要用 ,
隔开
输出结果
Hello, yoseya!
返回值
使用 return
语句可以使函数返回一个值
def add(a, b): # 定义函数及参数
c = a + b # 进行运算
return c # 返回值 x
x = add(3, 4) # 获取返回值(把函数返回的值赋值给 x)
print(x) # 输出 x
# 参数
# 传递参数
一般情况下调用函数时参数填写的顺序和函数定义时参数的位置一一对应,例如
def add(a, b):
...
add(3, 4)
调用函数时要向函数内传递参数(在括号中填写参数),参数填写的顺序和函数定义时的顺序一致,这里的 3
对应 a
,4
对应 b
关键词参数
还有一种传递参数方式叫关键词参数,它不需要考虑传参顺序。若是参数太多不方便一一对应的填写参数,就可以通过使用这种方式。
- 通过参数名称传递值,使得函数调用更加清晰和易读
def add(a, b):
...
add(a=3, b=4)
- 在定义函数时可以给参数设定默认值,拥有默认值的参数可以在调用时省略(不用填写)
def add(a, b, c=0):
...
add(a=3, b=4)
这里的 c
就是一个默认值为 0
的关键词参数,若调用函数是没有给参数 c
传入值,函数会按照默认值去处理,若传入了新的值,则会按照传入的值进行处理
- 关键词参数传入顺序可以任意,因为参数值对应着参数名所以就不需要通过传参顺序对应传入的参数了
def add(a, b, c):
...
add(b=3, c=1, a=4)
强制关键字参数
在函数定义时可以用 *
强制要求 *
之后的所有参数以关键词参数的形式传递
def add(a, b, *, c):
...
add(3, 4, c=1)
# 可变参数
一般的函数传参是一个萝卜一个坑,一个参数只能对应一个值,可变参数允许函数接受不确定数量的参数
可变参数由被细分为两种:可变位置参数和可变关键词参数
- 可变位置参数用
*args
的形式表示,传入的位置参数会被收集到一个元组中 - 可变关键词参数用
**kwargs
的形式表示,传入的关键字参数会被收集到一个字典中
def test(*args, **kwargs):
print(args, kwargs)
test(1, 2, 3, name="Alice", age=30)
输出结果
(1, 2, 3) {'name': 'Alice', 'age': 30}
注意
若要在一个函数中同时使用 *args
和 **kwargs
时 *args
必须在 **kwargs
之前
# 递归函数
递归函数是指一个函数在定义中调用自身的函数
在使用递归函数时要注意设置一个或多个递归的终止条件,不能使其成为死循环。为了确保程序的安全性,Python 设置了递归深度(通常为1000)可以通过 sys.setrecursionlimit
来调整,但不建议无限制增加,因为这可能会导致程序崩溃
这是一个用递归函数实现阶乘的例子,很明显,在最后一行代码时 factorial
函数调用了自己
def factorial(n):
if n == 0 or n == 1:
return 1
else:
return n * factorial(n - 1)
# 闭包
闭包是指一个内部函数访问其外部作用域中的变量。通常指在一个嵌套函数中,子函数访问父函数中的变量
这就是一个闭包的例子,子函数 b
中使用了父函数 a
的变量 x
def a(x):
def b(y):
return x + y
return b
c = a(10) # 相当于把函数 b 赋值给了 变量 c
s = c(5) # 相当于给函数 b 传参
print(s) # 输出 15d
- 内存泄漏:闭包会保留外部作用域的临时变量,如果这些变量占用大量内存且长时间不释放,可能会导致内存泄漏。
- 可读性和维护性:过度使用闭包可能会使代码变得复杂,影响可读性和维护性
# 高阶函数
# Lambda 函数
- 没有函数名,也称为匿名函数
- 代码简洁,只有一行
- 只能包含一个表达式
语法
lambda arguments: expression
- arguments:参数列表,可以有多个参数,用逗号分隔。
- expression:表达式,该表达式的值将作为 lambda 函数的返回值
单个参数
add_one = lambda x: x + 1
print(add_one(5)) # 输出 6
多个参数
add = lambda x, y: x + y
print(add(3, 4)) # 输出 7
无参数
greet = lambda: "Hello, World!"
print(greet()) # 输出 "Hello, World!"
# 装饰器
# 模块
# 导入模块
使用 import
导入整个模块
import math
使用 from ... import ...
导入特定成员
from math import sqrt
from
后面是模块名称,import
后面是模块成员的名称,成员可以是函数,类,变量,子模块等
可以同时导入一个模块中的多个模块成员,各国成员用 ,
隔开
from math import sqrt,cbrt,log
导入相同目录下的模块可以直接写模块名称,但使用模块中的函数时需要 Module.Function
的方式调用
# abcd.py
def printName(name):
print(f"Hello, {name}!")
# main.py
import abcd
abcd.printName("yoseya")
若是调用某个模块中某个类的静态方法时需要用 Module.Class.Function
的方式调用
# abcd.py
class MyClass:
@staticmethod
def printName(name):
print(f"Hello, {name}!")
# main.py
import abcd
abcd.MyClass.printName("yoseya")
若是使用 from ... import ...
导入了模块中的某个成员时就可以直接使用这个成员
from abcd import printName
printName("yoseya")
如果想要导入整个模块但又觉得使用 import
导入模块后调用模块成员麻烦,可以使用通配符 *
导入模块中的所有成员
from abcd import *
printName("yoseya")
导入子文件下的模块
.
├── main.py
└── lib
└── abcd.py
from lib.abcd import printName
# 特殊变量
特殊变量 | 说明 |
---|---|
__name__ | 表示所在模块的名称(主程序中值为 __main__ ,若在其他模块中值为该模块名称) |
__file__ | 表示模块文件路径 |
__doc__ | 获取模块,类,函数中的字符串注释(默认获取第一个字符串) |
__package__ | 表示当前模块所属的包名 |
__loader__ | 表示加载当前模块的模块加载器 |
__spec__ | 表示模块的规格(关于模块的各种元数据信息) |
# __name__
表示所在模块的名称,主要用于确定模块是否作为主程序运行,还是被其他模块导入
- 如果模块作为主程序运行,
__name__
的值为__main__
。 - 如果模块被其他模块导入,
__name__
的值为模块的名称。
.
├─ main.py
└─ abcd.py
# main.py
import abcd
# abcd.py
if __name__ == "__main__":
print(f"程序自身在运行 {__name__}")
else:
print(f"我来自另一模块 {__name__}")
当执行代码 main.py 时输出结果
我来自另一模块 abcd
# __doc__
该变量主要用于访问模块,类,函数中的文档字符串(就是用 """
括起来的多行注释),文档字符串通常用于提供描述性的注释,帮助开发者了解代码的功能和用法。
def abc():
"""这是第一个示例函数"""
"""这是第二个示例函数"""
pass
print(abc.__doc__)
输出结果
这是第一个示例函数
注意
若有多个多行注释 __doc__
默认获取第一个
# 面向对象编程
面向对象编程(Object-Oriented Programming,简称 OOP)是一种编程范式。它将实体抽象为对象,通过对象之间的交互来设计和构建软件系统。
举例
现在要设计一个银行账户管理系统,可以把账户作为对象,账户的账号,持有者,存款等都是账号的属性,根据这些属性来设计管理系统中的交互,然后把它们封装成一个类,这个类相当于一个模板,我们只需要把不同账户的数据输入这个模板中,程序就会根据输入的数据进行对应的操作或输出。这些输入的账户数据称作实例
# 类和实例
- 类是函数的集合,可以把多个函数封装到一块。
- 类里的函数被称为方法,类中的方法可以访问和使用类的属性。
- 类是创建实例的模板,实例是根据类创建的具体对象,各个实例间数据互相独立,互不影响
- 实例调用方法时,方法可以直接访问实例的数据
class Name(object):
类用 class
表示,后面跟着类名,()
里是继承的类(表示该类是从哪个类继承下来的),如果没有就默认是 object
(object
是所有类的基类,所有其他类都直接或间接地继承自 object
)python3 中所有类都默认继承自 object
所以也可以直接写成
class Name:
类中的第一个方法是 __init__
用于初始化对象,定义类的属性
例如,这段代码中有四个参数 self
, a
, b
,c
。
self
是__init__
的第一个参数,用于指代类的实例对象本身,self
是一个约定俗成的名称(这个名称可以自定义)a
,b
,c
是用户自定义的参数
class Student:
def __init__(self, a, b, c):
self.name = a # 姓名
self.sex = b # 性别
self.age = c # 年龄
这段代码为对象 self
的三个属性 name
,sex
,age
进行初始化,在之后的方法中可以直接使用这些定义好的属性
面向对象编程的一个重要特点就是数据封装。在 Student
类中,每个实例就拥有各自的 name
和 score
属性,我们可以通过函数来访问属性。这段代码中函数 adult
获取了 self.name
并对其进行判断
# 定义一个名为 Student 的类
class Student:
#初始化新创建的对象,并将参数赋值给相应的对象
def __init__(self, a, b, c):
self.name = a # 姓名
self.sex = b # 性别
self.age = c # 年龄
# 定义一个名为 adult 的方法,用于判断对象是否为成年人
def adult(self):
if self.age < 18:
print(f"{self.name}是未成年人")
else:
print(f"{self.name}是成年人")
# 创建两个 Student 的实例
XH = Student("小红", "女", 15)
XG = Student("小刚", "男", 20)
XH.adult() # 调用 XH 对象的 adult 方法
XG.adult() # 调用 XG 对象的 adult 方法
输出结果:
小红是未成年人
小刚是成年人
在面向对象编程中,可以通过调用对象的方法并向方法传递参数来执行特定的操作。
例如,在这段代码中,我们创建了两个 Student
类的实例 XH
和 XG
。然后,我们分别调用了这两个对象的 study
方法,并传递了不同的参数("物理" 和 "数学"),以显示每个学生正在学习的科目
# 定义一个名为 Student 的类
class Student:
#初始化新创建的对象,并将参数赋值给相应的对象
def __init__(self, a, b, c):
self.name = a # 姓名
self.sex = b # 性别
self.age = c # 年龄
# 定义一个名为 study 的方法,显示某人正在学习的科目
def study(self, subject):
print(f"{self.name}正在学习{subject}")
# 创建两个 Student 的实例
XH = Student("小红", "女", 18)
XG = Student("小刚", "男", 20)
XH.study("物理") # 调用 XH 对象的 study 方法
XG.study("数学") # 调用 XG 对象的 study 方法
输出结果:
小红正在学习物理
小刚正在学习数学
# 继承
一个类可以继承另一个类,获得其属性和方法。其中被继承的类叫做父类也叫基类,继承自父类的类叫做该类的子类(派生类)。
- 子类可以添加新的属性和方法,也可以重写基类的方法
- 一个类可以继承自多个基类
- 子类可以调用父类的方法,父类不能调用子类的方法
子类继承父类的属性
在下面这段代码中,eat 类继承自 Student 类,所以 eat 可以直接访问和使用 Student 的属性,当创建一个 eat 实例时,也需要填写 Student 中定义的三个参数。
# 定义一个名为 Student 的类
class Student:
# 初始化新创建的对象,并将参数赋值给相应的属性
def __init__(self, a, b, c):
self.name = a # 姓名
self.sex = b # 性别
self.age = c # 年龄
# 定义一个名为 eat 的类,该类继承自 Student 类
class eat(Student):
# 定义一个名为 speak 的方法,输出某人正在吃什么
def speak(self, food):
print(f"{self.name}正在吃{food}")
# 创建一个 eat 的实例
XM = eat("小明", "男", 20)
# 调用 XM 对象的 speak 方法,并传递参数 "包子"
XM.speak("包子")
输出结果:
小明正在吃包子
子类继承父类的方法
在这段代码中,eat
类中并没有 study
方法,但 eat
的实例却可以调用 study
方法,这是因为 eat
类继承自 Student
类,自然也继承了 Student
类中的方法
# 定义一个名为 Student 的类
class Student:
# 初始化新创建的对象,并将参数赋值给相应的属性
def __init__(self, a, b, c):
self.name = a # 姓名
self.sex = b # 性别
self.age = c # 年龄
# 定义一个名为 study 的方法,显示某人正在学习的科目
def study(self, subject):
print(f"{self.name}正在学习{subject}")
# 定义一个名为 eat 的类,该类继承自 Student 类
class eat(Student):
# 定义一个名为 speak 的方法,输出某人正在吃什么
def speak(self, food):
print(f"{self.name}正在吃{food}")
# 创建一个 eat 的实例
XM = eat("小明", "男", 20)
XG = eat("小刚", "男", 20)
XM.speak("包子") # 调用 XM 对象的 speak 方法,并传递参数 "包子"
XG.study("语文") # 调用 XG 对象的 study 方法,并传递参数 "语文"
输出结果:
小明正在吃包子
小刚正在学习语文
在子类中重写从父类中继承的方法
这段代码中子类 eat
继承自父类 Student
,同时也继承了父类中的 study
方法,但在子类 eat
中又创建了一个新的 study
方法,这个方法覆盖了原本从父类中继承的 study
方法,这就叫做重写。
重写只是在子类中用新的方法覆盖了从父类中继承的方法,并不是修改父类的方法,所以重写后的方法只在子类中生效。
class Student:
# 初始化新创建的对象,并将参数赋值给相应的属性
def __init__(self, a, b, c):
self.name = a # 姓名
self.sex = b # 性别
self.age = c # 年龄
# 定义一个名为 study 的方法,显示某人正在学习的科目
def study(self, subject):
print(f"{self.name}正在学习{subject}")
# 定义一个名为 eat 的类,该类继承自 Student 类
class eat(Student):
# 重写父类的 study 方法,显示某人已经学习了某个科目
def study(self, subject):
print(f"{self.name}已经学习了{subject}")
XM = Student("小刚", "男", 20) # 创建一个 Student 的实例
XG = eat("小刚", "男", 20) # 创建一个 eat 的实例
XM.study("数学") # 调用 XM 对象的 study 方法,并传递参数 "数学"
XG.study("数学") # 调用 XG 对象的 study 方法,并传递参数 "数学"
输出结果:
小刚正在学习数学
小刚已经学习了数学
根据结果分析,XM
是 Student
的实例,XG
是 eat
的 实例,同样使用 study
方法,但输出结果存在差异,这是因为 XM
调用的是 Student
中的 study
方法,XG
调用的 是在 eat
中重写的 study
方法
一个子类继承自多个父类
这段代码中的子类 Student
,继承自父类 Person
和 Study
,父元素分别为子元素提供了name
,sex
,age
,subject
四种属性,由于这四种属性并不是在同一个构造函数定义的,所以在子类中传参时就出现了矛盾,我们需要在子类中重新编写构造函数 __init__
确定好传参时参数的顺序
# 定义一个名为 Person 的类
class Person:
def __init__(self, name):
self.name = name # 姓名
# 定义一个名为 Study 的类
class Study:
def __init__(self, subject):
self.subject = subject # 学科
# 定义一个名为 Student 的类,继承自 Person 和 Study
class Student(Person, Study):
def __init__(self, name, subject):
# 调用父类的构造函数
Person.__init__(self, name)
Study.__init__(self, subject)
def speak(self):
print(f"{self.name}正在学习{self.subject}")
# 创建一个 Student 的实例
XM = Student("小明", "数学")
# 调用 XM 对象的 speak 方法
XM.speak()
输出结果:
小明正在学习数学
# 多态
多态是同一方法对不同的对象作出不同的响应
多态有两种形式,编译时多态(静态多态)和运行时多态(动态多态)
- 编译时多态通常通过方法重载(Overloading)实现。方法重载是指在同一个类中定义多个同名但参数列表不同的方法。编译器根据调用时传递的参数类型和数量来决定调用哪个方法
- 运行时多态通常通过方法重写(Overriding)实现。方法重写是指子类重新定义父类中的方法。运行时多态的关键在于使用父类引用指向子类对象,然后调用方法时,实际执行的是子类的方法。
这是一个运行时多态,有 dog
和 cat
两个对象,同时使用 sound
方法时输出结果不同
# 定义一个基类 Animal
class Animal:
def sound(self):
pass
# 定义一个子类 Dog
class Dog(Animal):
def sound(self):
print("Woof!")
# 定义一个子类 Cat
class Cat(Animal):
def sound(self):
print("Meow!")
# 创建 Dog 和 Cat 的实例
dog = Dog()
cat = Cat()
dog.sound()
cat.sound()
输出结果:
Woof!
Meow!
这是一个编译时多态,但在调用时你会发现,第一个输出出现了缺少参数的问题,因为 Python是一种动态类型语言,它只保留了最后一个定义的方法,之前两个参数的方法被覆盖了,这就导致 Python 并不能支持真正的编译时多态
class Calculator:
def add(self, a, b):
return a + b
def add(self, a, b, c):
return a + b + c
# 创建 Calculator 的实例
calc = Calculator()
print(calc.add(1, 2)) # TypeError: add() missing 1 required
print(calc.add(1, 2, 3)) # 输出: 6
# 访问限制
在 Python 中,类的访问限制主要通过命名约定来实现。访问限制有三个等级:
- 公有成员(Public):可以在类的外部自由访问和修改(默认)
- 受保护成员(Protected):名称以单个下划线
_
开头,表示该成员是受保护的,不应该在类的外部直接访问或修改,但 Python 并不会强制执行这一规则 - 私有成员(Private):名称以双下划线
__
开头,表示该成员是私有的,Python 会对其进行名称改写,使其在类的外部难以访问
做一个实验,代码如下
class MyClass:
def __init__(self):
self.public = 10
self._protected = 20
self.__private = 30
# 创建 MyClass 的实例
obj = MyClass()
# 访问公有成员
print(obj.public) # 输出: 10
# 访问受保护成员
print(obj._protected) # 输出: 20
# 访问私有成员
print(obj.__private) # 错误: AttributeError
# 通过名称改写访问私有成员
print(obj._MyClass__private) # 输出: 30
在测试中,我们会发现公有成员和受保护成员都可以直接在外部对类中的数据进行访问,只有私有成员不能访问,但如最后一行代码,在私有成员的名称前添加单下划线 _
加类名后就又可以访问类中的数据了,这进一步验证了Python 是通过对成员名称进行改写从而实现对其无法访问的,但通过给私有成员名称前增加类似于 _MyClass
的前缀从而实现访问的方法是不推荐的,因为不同版本的 Python 解释器,可能会对成员变量的名称进行不同的改写
通过这种方法不仅可以限制外部对类中成员变量的访问,还可以限制对类中方法的使用
class MyClass:
def public(self):
print("public")
def _protected(self):
print("protected")
def __private(self):
print("private")
# 创建 MyClass 的实例
obj = MyClass()
# 访问公有成员
obj.public() # 输出: public
# 访问受保护成员
obj._protected() # 输出: protected
# 访问私有成员
obj.__private() # 错误: AttributeError
# 通过名称改写访问私有成员
obj._MyClass__private() # 输出: private
若想要私有成员合法的访问时,正确的办法是在类中为访问它单独设立一个方法,代码中设立了一个方法 getPrivate
用来返回这个私有成员的值,这就相当于在内部专门设立了一个和外部渠道,这种方式只返回值,所以外部只能访问,不能修改,可以很好把控数据的使用。
class MyClass:
def __init__(self):
self.__private = 1
def getPrivate(self):
return self.__private
# 创建 MyClass 的实例
obj = MyClass()
print(obj.getPrivate())
若是要让外部对私有成员既可以修改又可以访问,也可以单独再设立一个修改私有成员的方法,代码中设立了一个方法 setPrivate
用于在类的内部给私有成员 __private
重新赋值。setPrivate
是内部人员要向内部的成员传达信息很容易,但在外部我们只能通过它向内部传达信息。
class MyClass:
def __init__(self):
self.__private = 1
def getPrivate(self):
return self.__private
def setPrivate(self, x):
self.__private = x
# 创建 MyClass 的实例
obj = MyClass()
obj.setPrivate(0) # 把私有成员 __private 的值修改为 0
print(obj.getPrivate()) # 输出:0
# 属性
在类中有两种属性,实例属性和类属性
实例对象的属性叫做实例属性,例如代码中的 self.name
class Student(object):
def __init__(self, name):
self.name = name
单独存在于类中的变量叫做类属性,例如代码中的 name
class Student(object):
name = 'Student'
类属性归类所有,类的所有实例都可以访问,以下是两种访问方式
# 类属性访问
print(Student.name)
# 实例属性访问
s = Student() # 创建实例 s
print(s.name)
注意
在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,一般情况下程序会先检查是否有实例属性,若没有再检查类属性
# 获取对象信息
函数 | 说明 |
---|---|
type() | 用于获取对象的类型 |
isinstance() | 用于检查对象是否是指定类型或其子类的实例,若是则返回 True 否则返回 False |
dir() | 用于获取对象拥有的属性和方法列表 |
# 数学运算
在 Python 中进行高级的数学运算时需要使用 Python 自带的数学函数库 math,它提供了许多标准数学函数,如 sin
, cos
, log
, exp
等可用于普通的数学运算
参考:math 函数库使用文档 (opens new window)
使用前需要先引入 math 数学函数库
import math
如果有更高级的数学运算需求可以使用 NumPy,它支持多种随机数生成方法,可用于多维数组操作,支持矢量化运算,广泛应用于科学计算、数据分析和机器学习等领域
参考:NumPy 用户指南 (opens new window)
NumPy 是一个第三方库,需要单独安装
pip install numpy
引入 NumPy 科学计算库
import numpy as np
如果你需要处理大规模数值数据并进行高效操作,建议使用 NumPy,如果你只需要简单的数学计算,可以使用 math
# 图表绘制
在 Python 中绘制图表需要引入专门的绘图库, Matplotlib 就是一个主流的绘图库,支持绘制静态,动态,可交互式的多种类型的图表
安装
pip install matplotlib
使用示例
假设一架飞机要在空中投掷炸弹,条件如下
列出计算公式:
求投掷炸弹后,
# 引入所需的库
import matplotlib.pyplot as plt
import numpy as np
# 设置参数
h = 3000
v0 = 200
g = 9.8
t = np.arange(0.0, 3.5, 0.01) # 设置时间(0 ~ 3.5s)
x = v0 * t # 计算横坐标
y = h - (1 / 2) * g * t**2 # 计算纵坐标
plt.plot(x, y) # 绘制点
plt.grid(True) # 显示网格
plt.xlabel("range (m)") # 设置x轴标签
plt.ylabel("height (m)") # 设置y轴标签
plt.title("Flight path of the bomb") # 设置标题
plt.savefig("pic.svg") # 保存文件
plt.show() # 显示图像
输出结果:
# 其他
# venv
venv
是 Python 自带的一个模块,用于创建虚拟环境。虚拟环境是一个独立的 Python 环境,其中包含了一个独立的 Python 解释器及其相关的库和包。这样可以避免不同项目之间的依赖冲突
venv 文件夹通常包含以下几个主要部分:
bin
包含了一些可执行脚本,如 activate(激活虚拟环境的脚本)、pip(包管理工具)等include
包含了一些头文件,用于编译 C 扩展等lib
包含了 Python 标准库和其他安装的第三方库pyvenv.cfg
包含了虚拟环境的一些配置信息,如 Python 版本等
# pyc
.pyc
文件是 Python 的编译文件
- 当 Python 脚本被运行时,Python 解释器会先将源代码(.py 文件)编译成字节码,然后保存为
.pyc
文件 .pyc
文件通常存储在__pycache__
目录下,以加快下次导入相同模块时的速度。.pyc
文件与具体的 Python 版本相关,不同版本的 Python 生成的.pyc
文件可能不兼容。- 可以直接运行
.pyc
文件