Python语言基础
01 序章
Python(英国发音:/ˈpaɪθən/;美国发音:/ˈpaɪθɑːn/),是一种广泛使用的解释型、高级和通用的编程语言。
Python支持多种编程范型,包括结构化、过程式、反射式、面向对象和函数式编程。它拥有动态类型系统和垃圾回收功能,能够自动管理内存使用,并且其本身拥有一个巨大而广泛的标准库。
它的语言结构以及面向对象的方法,旨在帮助程序员为小型的和大型的项目编写逻辑清晰的代码。
吉多·范罗苏姆(Guido van Rossum)是一名荷兰计算机程序员,他作为Python程序设计语言的作者而为人们熟知。他于1980年代后期开始研发Python。吉多·范罗苏姆于1991年首次发布 Python 0.9.0。Python 2.0于2000 年发布并引入了新功能。Python 3.0于2008年发布,它是该语言的主要修订版,并非完全向后兼容。Python 2于2020年随2.7.18版停止支持。
Python的设计哲学,强调代码的可读性和简洁的语法,尤其是使用空格缩进来划分代码块。相比于C或Java,Python让开发者能够用更少的代码表达想法。
02 环境搭建
2.1 Python安装
Python官方链接:https://www.python.org/
Windows版本:https://www.python.org/downloads/windows/
Python安装可以采用以下两种方式:
- 联网安装:在官方网站下载对应版本的安装包,一路next即可。
- 离线安装:在官网下载对应版本的压缩包,解压后运行安装程序,选择Add Python to PATH前打勾,然后点击Install Now即可。
2.2 PyCharm
PyCharm是一款非常好用的Python IDE集成开发环境,PyCharm是由JetBrains打造的一款Python IDE,PyCharm的目的是提高用户在使用Python语言开发时的效率,提供了一些工具,如调试、语法高亮、项目管理、代码跳转、智能提示、自动完成、单元测试、版本控制等。
2.3 小试牛刀:写一个小游戏
1 | ## 首先我们导入了Python内置的random模块,用来生成随机数。 |
小提示:在命令行中输入
dir(__builtins__)
就可以看到Python提供的内置函数啦!
03 基础语法
3.1 变量
- Python变量:变量用于存储某个或某些特定的值,它与一个特定标识符相关联,该标识符称为变量名称。
- 用字符串变量作为例子:字符串就是一系列字符,Python中的字符串用单引号或双引号括起来表示,如下所示:
1 | mystr = 'plays' |
3.2 数据类型
Python 是一种高级编程语言,其数据类型包括:
- 数字类型: 数字类型用于表示整数、浮点数和复数。在Python中,可以使用
int
、float
和complex
三个类型变量来分别表示整数、浮点数和复数。例如:
1 | a = 10 ## int变量 |
基础操作:
操作 | 结果 |
---|---|
x + y | x加y结果 |
x - y | x减y结果 |
x * y | x 乘以 y 的结果 |
x / y | x 除以 y 的结果 |
x // y | x 除以 y的结果,向下取整 |
x % y | x 除以 y 的余数 |
-x | x的相反数 |
+x | x本身 |
abs(x) | x的绝对值 |
int(x) | 将x转换成整数 |
float(x) | 将x转换成浮点数 |
complex(re,im) | 返回一个复数,re是实部,im是虚部 |
c.conjugate() | 返回c的共轭复数 |
divmod(x,y) | 返回(x // y, x % y) |
pow(x,y) | 计算x的y次方 |
x ** y | 计算x的y次方 |
- 字符串(str): 字符串是一组字符的序列,用引号括起来。在Python中,有两种类型的字符串:一种是单引号字符串,另一种是双引号字符串。它们之间没有任何区别,只是在定义字符串时用了不同的引号而已。例如:
1 | name = '小明' ## 单引号字符串 |
- 列表(list): 列表是一种有序的集合,用方括号括起来,元素之间用逗号分隔。列表可以包含不同类型的元素。例如:
1 | fruits = ['苹果', '香蕉', '橙子'] ## 包含三个元素的列表 |
- 元组(tuple): 元组是一种有序的集合,用圆括号括起来,元素之间用逗号分隔。元组一旦被创建后就不能修改。例如:
1 | colors = ('红', '绿', '蓝') ## 包含三个元素的元组 |
- 集合(set): 集合是一种无序的、不可重复的元素集合,用花括号括起来,元素之间用逗号分隔。集合可以被交、并、差等集合运算。例如:
1 | odd_numbers = {1, 3, 5, 7, 9} ## 包含五个奇数的集合 |
- 字典(dict): 字典是一种无序的、键值对映射的集合,用花括号括起来。字典中的每个元素都是一个键值对(key-value pair),键和值之间用冒号分隔。例如:
1 | grades = {'Alice': 90, 'Bob': 85, 'Charlie': 95} ## 包含三个键值对的字典 |
- 布尔型(bool): 布尔型只有两个取值:True 和 False。它用于表示真和假、是和不是、有和没有等对立的概念。例如:
1 | x = True ## 表示为真 |
运算符 | 含义 |
---|---|
and | 左边和右边同时为True,结果为True |
or | 左边或者右边其中一个为True |
not | 取反操作,not True结果为False,not False结果为True |
运算符优先级
优先级 | 运算符 |
---|---|
1 | 括号 () |
2 | 幂运算 ** |
3 | 一元运算符 +x, -x |
4 | 乘法、除法和取模运算 * / // % |
5 | 加法和减法运算 + - |
6 | 位运算 << >> & | ^ ~ |
7 | 比较运算 < <= > >= == != |
8 | 逻辑运算符 not and or |
9 | 赋值运算符 = += -= *= /= //= %= **= |
3.3 条件判断(分支)
1 | ## 输入一个数,并且打印它是负数、0、还是正数,并输出它的绝对值 |
注意:本示例代码中使用了
int()
函数将用户输入的字符串转换为整数类型。如果输入的字符串不能转换为整数类型,将会抛出ValueError
异常。在实际应用中,我们需要根据具体情况编写合适的异常处理代码,保证程序的健壮性。
3.4 循环
在Python中,有几种不同的循环结构可供使用,每种结构都有其特定的用途和语法。以下是Python中可用的循环结构:
for
循环:用于遍历任何可迭代的对象,例如列表、元组、字典等。语法如下:
1 | for variable in iterable: |
while
循环:用于在条件为真时重复执行一组语句。语法如下:
1 | while condition: |
for
…in
…range()
循环:用于遍历一个指定范围内的数字。语法如下:
1 | for i in range(start, stop, step): |
其中,start
参数表示范围的起始值,stop
参数表示范围的结束值(不包括在范围内),step
参数表示步长。如果不指定步长,默认为1。
for
…in
循环:用于遍历一个对象的属性或键。语法如下:
1 | for key in dict: |
其中,dict
表示要遍历的字典对象,key
表示字典的键。
在使用循环结构时,请确保您已经明确知道要执行的步骤,以及循环的结束条件。否则,程序可能会进入无限循环,导致死循环。
关于Python序列的小知识:
Python的序列是指一块可存放多个值的连续内存空间。
Python中的序列类型包括字符串、列表、元组、集合和字典。
这些序列支持以下几种通用的操作:
- 索引:通过每个值所在位置的编号访问它们。
- 切片:截取序列中的一部分。
- 相加:将两个序列合并成一个新序列。
- 相乘:返回由重复的序列元素组成的新序列。
比较特殊的是,集合和字典不支持索引、切片、相加和相乘操作。
3.5 列表
Python中的列表(List)是一种可变序列类型,可以用来存储一组有序的数据。列表中的元素可以是任何类型,包括数字、字符串、布尔值、列表等。
以下是Python中列表的一些基本操作:
创建列表:
1 | my_list = [1, 2, 3, "four", "five"] |
访问列表中的元素:
1 | my_list[0] ## 访问第一个元素,输出 1 |
修改列表中的元素:
1 | my_list[1] = "two" |
删除列表中的元素:
1 | del my_list[3] ## 删除第三个元素 |
列表切片:
1 | my_list[1:3] ## 访问第二个到第三个元素,输出 [2, 3] |
列表长度和判断是否为空:
1 | len(my_list) ## 输出列表的长度,输出 5 |
访问列表中的元素:
1 | my_list[0] ## 访问第一个元素,输出 1 |
修改列表中的元素:
1 | my_list[1] = "two" |
删除列表中的元素:
1 | del my_list[3] ## 删除第三个元素 |
列表切片:
1 | my_list[1:3] ## 访问第二个到第三个元素,输出 [2, 3] |
列表长度和判断是否为空:
1 | len(my_list) ## 输出列表的长度,输出 5 |
这些是一些常用的列表操作。还有很多其他的操作可以使用,比如使用列表作为函数参数、返回值,以及使用内置函数对列表进行排序、查找最大值和最小值等操作。
3.6 元组
Python中的元组(tuple)是一种不可变序列类型,类似于列表(list),但与列表不同的是,元组一旦创建就不能修改。
以下是创建元组的两种方式:
使用圆括号将元素括起来,用逗号分隔:
1 | my_tuple = (1, 2, 3, "hello") |
使用元组字面量(tuple literal)表示法,在元素后面加上一个逗号:
1 | my_tuple = 1, 2, 3, "hello" |
和列表一样,元组也可以通过索引访问其元素:
1 | print(my_tuple[0]) ## 输出 1 |
元组也可以用加号运算符进行拼接:
1 | my_tuple = (1, 2, 3) + ("hello", "world") |
元组还可以用内置函数tuple()将其他可迭代对象转换为元组:
1 | my_list = [1, 2, 3, "hello"] |
以下是一些常用的元组函数:
函数名称 | 说明 |
---|---|
len(tuple) | 返回元组中元素的数量。 |
tuple(iterable) | 将可迭代对象转换为元组。 |
tuple.index(value) | 返回元组中第一个匹配给定值的元素的索引。 |
tuple.count(value) | 统计元组中指定值的出现次数。 |
这些函数可以用于对元组进行一些基本的操作,如获取元组的长度、查找元素的索引以及统计元素出现的次数。由于元组是不可变的,所以没有直接修改元组的函数。
3.7 字符串
Python中的字符串是一系列字符序列,被包含在两个引号(单引号或双引号)之间。
例如:
1 | my_string = 'Hello, world!' |
在Python中,字符串是不可变的,这意味着一旦一个字符串被创建,就不能再修改它的字符。但是,可以使用字符串的拼接、格式化和替换等方法来创建新的字符串。
例如,可以使用加号(+)运算符来连接两个字符串:
1 | first_name = 'Alice' |
可以使用字符串的format()方法来格式化字符串,例如:
1 | name = 'Alice' |
还可以使用字符串的replace()方法来替换字符串中的子字符串,例如:
1 | text = 'The quick brown fox jumps over the lazy dog.' |
需要注意的是,在Python中,字符串和数字等数据类型是不同的,因此不能将它们直接相加或连接。如果要将字符串转换为数字,可以使用int()、float()等内置函数。如果要将数字转换为字符串,可以使用str()函数。
以下是一些常用的字符串函数:
函数名称 | 说明 |
---|---|
len(str) | 返回字符串的长度。 |
str.upper() | 将字符串中的所有字母转换为大写。 |
str.lower() | 将字符串中的所有字母转换为小写。 |
str.capitalize() | 将字符串的首字母转换为大写,其他字母转换为小写。 |
str.title() | 将字符串中每个单词的首字母转换为大写。 |
str.isupper() | 检查字符串中的所有字母是否都是大写。 |
str.islower() | 检查字符串中的所有字母是否都是小写。 |
str.isalpha() | 检查字符串是否只包含字母字符。 |
str.isdigit() | 检查字符串是否只包含数字字符。 |
str.isalnum() | 检查字符串是否只包含字母和数字字符。 |
str.startswith(prefix) | 检查字符串是否以给定的前缀开头。 |
str.endswith(suffix) | 检查字符串是否以给定的后缀结尾。 |
str.strip() | 去除字符串开头和结尾的空白字符。 |
str.split() | 将字符串按照指定的分隔符拆分成列表。 |
str.join(iterable) | 使用字符串作为连接符,将可迭代对象中的元素连接成一个字符串。 |
str.replace(old, new) | 将字符串中的指定子串替换为新的子串。 |
str.find(sub) | 在字符串中查找子串第一次出现的位置,并返回索引值。 |
str.rfind(sub) | 在字符串中从右边开始查找子串第一次出现的位置,并返回索引值。 |
str.count(sub) | 统计字符串中指定子串出现的次数。 |
str.isnumeric() | 检查字符串是否只包含数字字符。 |
这只是一部分常见的字符串函数,Python还提供了更多用于字符串处理和操作的函数。你可以查阅Python的官方文档来获取完整的字符串函数列表和详细的用法说明。
3.8 字典
Python字典是Python中的一种内置数据类型,用于存储具有映射关系的数据。
Python字典以键值对的形式存储数据,其中键和值可以是任何不可变数据类型,如整数、浮点数、字符串等。
字典中的键必须是唯一的,而值可以重复。
Python字典的创建可以使用花括号语法或dict()函数,例如:
1 | ## 使用花括号语法创建字典 |
1 | my_dict = {'apple':1, 'banana': 2, 'orange': 3} |
函数名称 | 说明 |
---|---|
dict() | 创建一个新的空字典。 |
dict(key1=value1, key2=value2, …) | 创建一个带有指定键值对的字典。 |
len(dict) | 返回字典中键值对的数量。 |
dict.keys() | 返回一个包含字典所有键的可迭代对象。 |
dict.values() | 返回一个包含字典所有值的可迭代对象。 |
dict.items() | 返回一个包含字典所有键值对的可迭代对象,每个键值对表示为元组。 |
dict.get(key, default) | 获取指定键的值,如果键不存在,则返回默认值。 |
dict.setdefault(key, default) | 获取指定键的值,如果键不存在,则设置默认值并返回默认值。 |
dict.update(other_dict) | 将另一个字典中的键值对更新到当前字典中。 |
dict.pop(key, default) | 删除指定键并返回对应的值,如果键不存在,则返回默认值。 |
dict.popitem() | 随机删除并返回字典中的一个键值对。 |
dict.clear() | 清空字典中的所有键值对。 |
dict.copy() | 创建字典的浅拷贝副本。 |
dict.fromkeys(iterable, value) | 创建一个新字典,使用可迭代对象中的元素作为键,指定的值作为所有键的默认值。 |
dict.setdefault(key, default) | 获取指定键的值,如果键不存在,则设置默认值并返回默认值。 |
这只是一部分常见的字典函数,Python还提供了更多用于字典处理和操作的函数。你可以查阅Python的官方文档来获取完整的字典函数列表和详细的用法说明。
3.9 集合
在Python中,集合(set)是一种无序的、不可重复的数据类型,用于存储一组唯一的元素。与列表(list)不同,集合中的元素不能重复,而且元素的顺序不起作用。
创建集合的方式是使用一对大括号{},在大括号内包含要存储在集合中的元素。例如:
1 | my_set = {1, 2, 3, 4, 4} ## 注意4重复出现了,但只算一个元素 |
可以使用add()方法向集合中添加元素,例如:
1 | my_set = {1, 2, 3, 4} |
也可以使用update()方法将一个集合中的元素添加到另一个集合中,例如:
1 | set1 = {1, 2, 3} |
还可以使用remove()方法从集合中删除元素,例如:
1 | set1 = {1, 2, 3, 4} |
1 | my_set1 = {1, 2, 3, 4, 5} |
需要注意的是,如果集合中要删除的元素不存在,会抛出ValueError异常。
除了上述操作,集合还支持其他方法,例如len()、in关键字、foreach等。此外,还可以使用循环语句(如for循环或while循环)来遍历集合中的元素。
函数名称 | 说明 |
---|---|
set() | 创建一个新的空集合。 |
set(iterable) | 创建一个包含可迭代对象中元素的集合。 |
len(set) | 返回集合中元素的数量。 |
set.add(element) | 向集合中添加元素。 |
set.remove(element) | 从集合中移除指定元素,如果元素不存在会抛出KeyError异常。 |
set.discard(element) | 从集合中移除指定元素,如果元素不存在则不会抛出异常。 |
set.clear() | 清空集合中的所有元素。 |
set.pop() | 随机移除并返回集合中的一个元素。 |
set.copy() | 创建集合的浅拷贝副本。 |
set.union(other_set, …) | 返回多个集合的并集。 |
set.intersection(other_set, …) | 返回多个集合的交集。 |
set.difference(other_set, …) | 返回当前集合与其他集合的差集。 |
set.symmetric_difference(other_set) | 返回当前集合与另一个集合的对称差集,即两个集合中不重复的元素的集合。 |
set.issubset(other_set) | 判断当前集合是否是另一个集合的子集。 |
set.issuperset(other_set) | 判断当前集合是否是另一个集合的超集。 |
set.isdisjoint(other_set) | 判断当前集合和另一个集合是否没有交集。 |
set.update(other_set, …) | 将多个集合的元素添加到当前集合中。 |
set.intersection_update(other_set, …) | 修改当前集合,使其只包含与其他指定集合相交的元素。 |
set.difference_update(other_set, …) | 修改当前集合,移除与其他指定集合相同的元素。 |
set.symmetric_difference_update(other_set) | 修改当前集合,移除与另一个指定集合相同的元素,并将两个集合中不重复的元素合并到当前集合中。 |
这只是一部分常见的集合函数,Python还提供了更多用于集合处理和操作的函数。你可以查阅Python的官方文档来获取完整的集合函数列表和详细的用法说明。
3.10 函数
在Python中,函数是一段可重复使用的代码块,用于执行特定的任务或解决特定的问题。函数可以接受输入参数,执行一系列操作,并返回结果。
以下是一个简单的Python函数示例:
1 | def add_numbers(x, y): |
这个函数名为add_numbers,它接受两个输入参数x和y,将它们相加并返回结果。
函数的定义由关键字def和函数名称开始,后面跟着括号,括号中可以包含参数列表。冒号后面缩进的代码块是函数的主体,它包含要执行的代码。
这个函数使用文档字符串来描述它的目的。文档字符串是放在函数定义前面的三重引号字符串,用来描述函数的作用、参数、返回值等信息。在上面的示例中,文档字符串描述了函数将两个数字相加并返回结果。
可以在需要使用该函数的地方调用它。例如:
1 | result = add_numbers(3, 5) |
这里调用了add_numbers函数并将参数3和5传递给它。函数返回结果8,将其赋值给变量result,并使用print函数输出结果。
在Python中,函数可以使用不同的参数列表、不同的名称、不同的返回类型等来执行不同的任务。这就是Python函数的灵活性所在。
3.11 闭包
Python闭包是指一个函数以及其捆绑的周边环境状态(词法环境)打包成一个对象,并且这个对象可以被引用,或者这个对象可以解除捆绑,释放周边环境状态。
说得简单点,闭包就是一个函数嵌套了另一个函数,并且内部函数使用了外部函数的变量(非全局变量)且外部函数的返回值是内部函数的引用。
当然可以,下面是一个简单的Python闭包示例:
1 | ## 闭包:外部函数返回内部函数 |
在这个例子中,outer_func定义了一个闭包,它返回了一个内部函数inner_func的引用。inner_func函数返回了一个基于外部变量x的值,而外部变量x在外部函数outer_func中定义。
当outer_func被调用后,它返回了内部函数inner_func的引用,并将其赋值给变量closure。然后,我们通过调用closure()函数来执行内部函数,这将返回x + 1的结果,即2。
由于Python的闭包特性,内部函数inner_func现在可以访问外部函数outer_func中的变量x,即使outer_func已经返回并且其局部变量x已经销毁。这就是闭包的“封装的”效果——内部函数与外部变量的环境状态被一起打包到了闭包中。
3.12 装饰器
以下是一个简单的Python装饰器示例:
1 | def my_decorator(func): |
在这个示例中,my_decorator是一个装饰器函数,它接受一个函数作为参数并返回一个新的函数wrapper。wrapper函数在调用原始函数之前和之后都会打印一些文本。
@my_decorator语法是将my_decorator应用于say_hello函数的装饰器。这意味着say_hello函数将被包装在一个调用wrapper函数的过程中。
当我们调用say_hello()时,输出将是:
1 | Something is happening before the function is called. |
这个简单的示例展示了装饰器如何使用,以及它们在Python中的工作方式。
3.13 lambda表达式
在Python中,lambda表达式是一种创建匿名函数的方式,也称为“函数字面量”。它们允许您在编写代码时避免使用显式函数定义,从而简化代码并提高可读性。
lambda表达式的语法如下:
1 | lambda arguments: expression |
其中,arguments是函数参数列表,expression是函数体。例如,下面是一个简单的lambda函数,将输入的数字加1并返回结果:
1 | inc = lambda x: x + 1 |
在这个例子中,inc是一个lambda函数,它接受一个参数x并将其加1后返回结果。您可以将该lambda函数用于任何需要将数字加1的场景,而无需编写一个显式的函数定义。
lambda表达式通常用于处理简单的逻辑或操作,其中使用lambda函数比创建一个完整的功能定义更有意义。注意,尽管lambda函数非常适合小型任务,但对于更复杂的操作或需要重复调用的函数,定义一个显式函数可能更为可取。
3.14 生成器
在 Python 中,生成器(Generator)是一种特殊的迭代器,可以用于生成一系列值而不是一次性生成所有值。通过生成器,可以在迭代过程中逐步生成数据,从而减少内存的占用,提高程序的效率。
生成器是通过函数实现的,使用 yield 语句可以将函数转换为生成器,当调用生成器的 next() 方法时,生成器会执行一次,返回 yield 语句后面的值,并暂停执行状态,等待下一次调用 next() 方法。每次调用 next() 方法都会从上一次暂停的位置继续执行,直到函数执行完毕或遇到 return 语句。
下面是一个简单的生成器示例:
1 | def my_generator(): |
可以看到,在生成器函数中使用 yield 语句可以逐步生成数据,而在使用生成器时可以通过 next() 方法逐个获取这些数据。
3.15 递归
当然可以,以下是一个简单的Python递归函数示例,用于计算一个整数的阶乘:
1 | def factorial(n): |
该函数首先检查输入参数n是否等于1,如果是,则返回1作为结果。否则,它将调用自身来计算(n-1)的阶乘,并将结果与n相乘,从而得到n的阶乘。这个过程会一直持续下去,直到n等于1为止。
3.16 函数文档、类型注释、内省
Python 中的函数文档、类型注释和内省都是关于编写优质代码的工具,帮助 Python 开发人员更好地理解和重用代码。
1、函数文档:函数文档是函数的说明,用于描述函数的功能、参数和返回值等信息。在Python中,函数文档通常使用多行字符串或注释形式编写,并通过__doc__
属性来访问。
1 | def greet(name): |
2、类型注释:类型注释是在函数定义中使用特定语法来标注参数和返回值的类型信息。虽然类型注释在Python中是可选的,但它们可以提供有关函数的类型信息,使得代码更易于理解和维护。
1 | def add(a: int, b: int) -> int: |
3、内省:内省是指在运行时获取对象的信息的能力。在Python中,可以使用内省来获取函数的参数列表、默认参数值和函数签名等信息。
1 | import inspect |
函数文档、类型注释和内省都是 Python 开发者编写高质量代码的工具。它们让代码更易于理解、重用和维护。在实际开发中,应该尽可能地提供这些信息,以帮助其他开发者更好地使用和扩展您的代码。
3.17 高阶函数
Python中的高阶函数是指那些可以接受其他函数作为参数的函数。
高阶函数可以将一个函数作为参数传入,并且这个函数可以对一个或多个序列中的元素进行操作。map()函数就是高阶函数的一个例子,它根据提供的函数对指定序列做映射。
1 | ## 高阶函数例子: |
1 | ## 函数作为返回值例子: |
使用高阶函数的作用:对一个或多个序列中的元素进行操作时,比如说替换、筛选、求和,那么我们就可以将使用高阶函数,那么高阶函数的第一个参数必须为函数,第二个参数为一个或多个可迭代对象。
3.18 永久存储
Python中,永久存储指将数据存储在计算机中,并在程序重新启动时保留数据。这通常涉及使用文件、数据库或其他类似持久存储的机制。
以下是一些Python中实现永久存储的方法:
- 文件存储:使用Python内置的文件操作函数,如
open()
和close()
,可以将数据写入文件并在需要时读取它们。可以使用不同的模式(如写模式、追加模式等)来控制数据的写入和读取方式。 - 数据库存储:使用Python中的数据库API(如SQLite、MySQL或PostgreSQL),可以将数据存储在数据库中,并在需要时查询和更新它们。
- 对象存储:使用云存储服务(如七牛、Amazon S3、Google Cloud Storage等)或类似的库,可以将数据存储在远程服务器上,并在需要时下载或上传它们。
无论使用哪种方法,都需要考虑数据的格式、压缩方式、访问权限、持久性等方面的问题。
当我们在对文件读写时,通常是指从本地磁盘或其他存储设备中读取和写入数据。
下面是Python中读写文件的常用方法:
1 | ## 读取文件例子 |
1 | ## 写入文件例子: |
这里我们使用了Python内置的open()函数来打开文件。第一个参数是文件路径,第二个参数是打开文件的模式。
‘r’代表读模式,即从文件中读取数据。
‘w’代表写模式,即向文件中写入数据。
如果文件不存在,则会创建一个新文件。如果文件已经存在,则会覆盖原有内容。
在读写文件后,一定要及时关闭文件。这可以通过调用close()方法来实现。
如果不关闭文件,可能会导致数据丢失或破坏。
3.19 异常处理
在Python中,异常是在程序运行时出现的错误或问题的标志。这些异常会导致程序停止执行,除非处理它们的代码被编写并且被调用。因此,在编写Python代码时,异常处理非常重要。
Python中的异常处理通过try和except语句来实现。try语句用于包含可能引发异常的代码块,而except语句用于包含处理异常的代码块。以下是一个简单的异常处理示例:
1 | try: |
在上面的代码中,try语句块中的代码尝试将用户输入的字符串转换为整数,并计算100除以输入值的结果。如果这个过程出现任何异常,程序将跳转到except语句块中的一个异常处理程序。如果try语句块中的代码没有引发任何异常,那么程序将跳过所有的except语句块,执行最后的finally语句块中的代码。
在Python中,还有其他的处理异常的方式和方法,例如使用raise语句可以抛出新的异常,使用try…else语句可以在没有异常发生时执行代码块等等。在编写Python代码时,一定要考虑到异常处理的重要性,并使用适当的异常处理技术来确保程序的健壮性和可靠性。
小知识:Python是一种面向对象的编程语言,它的最基本概念之一就是类和对象。类是一种模板,它定义了对象的属性和方法,而对象则是类的实例化。在Python中,类和对象是创建高级程序的基础,因此了解它们的工作原理和使用方法非常重要。
3.20 类和对象
3.20.1 类的创建
类的基本概念和定义方法
Python中,类可以理解成是一种模板,对象就是以该模板生产出来的实例。类封装了数据和操作数据的方法。提供了一种将数据和功能组合在一起的方式,使得我们可以更方便地管理和使用数据。类的属性和方法
在Python中,类的属性通常是指变量,而方法则是用来操作这些变量的函数。1
2
3
4
5
6
7
8
9
10
11
12class MyClass:
my_attribute = "Hello"
def my_method(self):
print("Hello, world!")
my_object = MyClass()
## 类的属性可以通过点号.来访问,例如:
print(my_object.my_attribute) ## 输出 "Hello"
## 类的方法可以通过点号和括号来调用,例如:
my_object.my_method() ## 输出 "Hello, world!"类的访问修饰符
在Python中,类的访问修饰符用于控制类成员(属性和方法)的可访问性。Python提供了三种主要的访问修饰符:分别是Public、Protected、Private1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40class MyClass:
def __init__(self):
## 公有访问属性
self.public_var = 10
## 受保护访问属性
self._protected_var = 30
## 私有访问属性
self.__private_var = 20
## 公有访问修饰符(Public): 没有前缀,类的所有成员默认为公有成员。
## 公有成员可以在类内部、外部访问。
def public_method(self):
print("This is a public method")
## 私有访问修饰符(Private): 在属性或方法名称前加上双下划线(__)作为前缀。
## 私有成员只能在类内部访问,外部无法直接访问。
def _protected_method(self):
print("This is a protected method")
## 私有访问修饰符(Private): 在属性或方法名称前加上双下划线(__)作为前缀。
## 私有成员只能在类内部访问,外部无法直接访问。
def __private_method(self):
print("This is a private method")
obj = MyClass()
## 调用了公有钥属性和公有方法
print(obj.public_var) ## 输出: 10
obj.public_method() ## 输出: This is a public method
## 调用了私有属性和私有方法
## 报错: AttributeError: 'MyClass' object has no attribute '__private_var'
print(obj.__private_var)
## 报错: AttributeError: 'MyClass' object has no attribute '__private_method'
obj.__private_method()
## 尽管无法直接访问私有成员,但可以通过间接方式访问,例如使用特殊的名称重写机制(name mangling):
print(obj._MyClass__private_var) ## 输出: 20
obj._MyClass__private_method() ## 输出: This is a private method
## 注意:虽然私有成员可以通过以上方式访问,但通常不建议在实际使用中这样做,以遵循类的封装性原则。
请注意,这些访问修饰符并不像在某些其他编程语言中那样具有强制性。它们主要是作为一种约定来使用的,以标识类成员的预期访问级别。实际上,可以通过直接访问来访问所有类型的成员,但不鼓励这样做,应遵循类的封装性原则,使用适当的访问修饰符来限制访问权限。
3.20.2 继承
在Python中,类的继承是一种基于现有类定义新类的机制。子类可以继承父类的所有非私有属性和方法,并且可以重写和添加自己的属性和方法。
以下是一个简单的例子,展示了类的继承如何使用:
1 | ## 定义一个父类 Animal |
在上面的例子中,Dog
类继承了 Animal
类,因此 Dog
类自动拥有了 Animal
类中的所有非私有属性和方法。同时,Dog
类还重写了 Animal
类中的 eat
方法,并添加了自己的方法 bark
。在子类中调用父类的方法时,可以使用 super()
函数来调用父类的构造函数。
3.20.3 多态
在Python中,类的多态指的是同一个方法在不同类的实现中具有不同的行为。这可以通过继承和重写方法来实现。
例如,考虑以下两个类:
1 | ## 形状 |
在这个例子中,Shape
类有一个抽象方法 area
,它没有实现。Circle
和 Rectangle
类都继承了 Shape
类并重写了 area
方法。因此,Circle
和 Rectangle
类的对象都可以赋值给 Shape
类型的变量,这就是多态的体现。
3.20.4 多重继承
在Python中,一个类可以同时继承自多个父类,这就是多重继承。多重继承的语法是在类定义时列出多个父类,用逗号分隔,如下所示:
1 | class ChildClass(Parent1, Parent2, Parent3): |
在多重继承中,子类会继承所有父类的属性和方法。如果多个父类中有相同的方法,则子类会优先使用第一个父类中的方法。如果想要使用其他父类中的同名方法,可以使用super()
函数进行调用。
需要注意的是,多重继承可能会导致方法调用的混乱。如果一个父类的方法被子类重写了,但是在其他父类中又调用了该方法,那么可能会导致意料之外的行为。因此,在使用多重继承时需要谨慎处理方法调用的顺序和逻辑。
3.20.5 组合
在Python中,类的组合指的是将一个类的对象作为另一个类的属性,从而实现对另一个类的复用。类的组合可以帮助我们更好地组织代码,提高代码的复用性和可维护性。
例如,假设有一个Car
类,它有一个engine
属性表示引擎,我们可以将engine
定义为另一个类Engine
的对象,然后将Engine
类的对象作为Car
类的一个属性,如下所示:
1 | ## 发动机 |
在上面的例子中,Car
类接受一个Engine
类的对象作为构造函数的参数,并将它赋值给Car
类的一个属性engine
。然后,Car
类定义了一个start
方法,该方法调用了engine
对象的start
方法,并输出一条消息表示汽车正在启动。
使用类的组合可以使代码更加清晰和易于维护。通过将相关的对象组合在一起,我们可以更好地组织代码并减少冗余。
3.20.6 绑定
在Python中,类的绑定指的是将一个类的实例方法绑定到特定的实例对象上。通过绑定,我们可以将方法与特定的实例关联起来,以便在调用方法时直接访问该实例的属性和方法。
例如,假设有一个Person
类,它有一个greet
方法用于打招呼。我们可以将greet
方法绑定到特定的Person
实例上,如下所示:
1 | class Person: |
在上面的例子中,我们创建了两个Person
类的实例person1
和person2
,并将它们的greet
方法分别绑定到它们自己身上。因此,当我们调用person1.greet()
和person2.greet()
时,它们会分别输出不同的问候语。
通过类的绑定,我们可以更加灵活地操作类的实例方法,从而更好地控制对象的生命周期和行为。
3.20.7 重写
在Python中,重写(Override)指的是子类重新定义(或覆盖)从父类继承的方法或属性。当子类定义了一个与父类同名的方法或属性时,这个方法或属性就会覆盖父类中的同名方法或属性。
重写通常用于实现多态性,即根据对象的类型来决定调用哪个方法。在Python中,重写的方法可以通过super()
函数调用父类的方法,从而实现方法的继承和扩展。
以下是一个简单的示例,演示了如何在子类中重写父类的方法:
1 | class Animal: |
在上面的示例中,Dog
类继承了Animal
类,并重写了speak()
方法。当我们调用dog.speak()
时,输出结果为The dog barks
,而不是The animal speaks
。
3.20.8 鸭子类型
在Python中,鸭子类型(duck typing)是指一种编程风格,其中不关心对象的确切类型,而是关注它提供了什么方法或属性,并且仅依赖于这些方法或属性来确定对象的行为。这种风格的命名来源于鸭子,因为鸭子看起来像鸭子,走起来像鸭子,叫起来也像鸭子,即使它没有被明确地归类为鸭子,我们仍然可以把它当作鸭子来对待。
在Python中,鸭子类型通常通过以下方式实现:
- 无需显式地定义类型,只需要根据对象提供的方法或属性来确定其类型。
- 代码通常不依赖于对象的类型,而是依赖于对象提供的方法或属性。
- 代码通常不使用类型声明或类型检查,而是依赖于运行时检查来确定对象的类型。
例如,考虑以下代码片段:
1 | def process_item(item): |
在这个例子中,我们定义了一个process_item
函数,它接受一个参数item
。我们不关心item
的确切类型,只要它提供了process
方法,我们就可以调用它。这个函数使用了鸭子类型,因为我们只关注item
是否提供了process
方法,而不关心它的确切类型。
3.20.9 __slots__
在Python中,类的__slots__
是一个类属性,用于定义该类实例的属性限制。通过在类定义中添加__slots__
属性,可以限制该类实例的属性数量,从而节省内存空间。
具体来说,__slots__
应该是一个由字符串组成的元组,每个字符串表示一个属性名。当一个类定义了__slots__
属性后,该类实例将不再具有普通的字典行为,而是只能通过指定的属性名来访问属性。
以下是一个示例代码:
1 | class Person: |
在上面的代码中,我们定义了一个Person
类,并使用__slots__ = ('name', 'age')
限制了该类实例的属性名。因此,该类实例只能通过name
和age
属性来访问属性,而不能通过其他属性名来访问。
3.20.10 魔术方法
在Python中,类的魔术方法(Magic Methods)是一些特殊方法,它们以双下划线开头和结尾,用于扩展类的基本功能。以下是一些常用的类的魔术方法:
__init__(self, ...)
:类的构造函数,用于初始化实例属性。__str__(self)
:返回实例的字符串表示形式,通常用于打印输出。__repr__(self)
:返回实例的官方字符串表示形式,通常用于调试和开发。__len__(self)
:返回实例的长度。__getitem__(self, key)
:通过索引获取实例的属性或值。__setitem__(self, key, value)
:设置实例的属性或值。__sub__(self, other)
:实现减法操作。__mul__(self, other)
:实现乘法操作。__div__(self, other)
:实现除法操作。__eq__(self, other)
:实现相等操作符(==)的比较。__ne__(self, other)
:实现不相等操作符(!=)的比较。__lt__(self, other)
:实现小于操作符(<)的比较。__le__(self, other)
:实现小于等于操作符(<=)的比较。__gt__(self, other)
:实现大于操作符(>)的比较。__ge__(self, other)
:实现大于等于操作符(>=)的比较。
这些魔术方法可以用于自定义类的行为,例如自定义对象的字符串表示形式、索引、比较等操作。
以下是一些Python中类的魔术方法的例子:
- 自定义对象的字符串表示形式:
1 | class Person: |
在上面的例子中,我们定义了一个Person
类,并使用__str__
方法自定义了对象的字符串表示形式。当我们打印Person
类的实例时,将使用该方法返回的字符串表示形式。
- 自定义对象的索引操作:
1
2
3
4
5
6
7
8
9class MyList:
def __init__(self, values):
self.values = values
def __getitem__(self, index):
return self.values[index]
def __setitem__(self, index, value):
self.values[index] = value
在上面的例子中,我们定义了一个MyList
类,并使用__getitem__
和__setitem__
方法实现了类似列表的索引操作。我们可以像访问列表一样访问MyList
类的实例。
- 自定义对象的大小比较:
1 | class Point: |
在上面的例子中,我们定义了一个Point
类,并使用__lt__
方法实现了对象的大小比较。我们可以使用小于号(<)对两个Point
类的实例进行比较。
3.20.11 属性访问
在Python中,属性访问是一种访问对象的属性或值的方式。可以使用点号(.)来访问对象的属性。例如,如果有一个名为obj的对象,它有一个名为name的属性,则可以使用以下方式来访问该属性:
1 | obj.name |
如果属性名包含特殊字符或空格,可以使用方括号([])来访问。例如,如果有一个名为obj的对象,它有一个名为“first name”的属性,则可以使用以下方式来访问该属性:
1 | obj["first name"] |
除了使用点号或方括号来访问属性之外,还可以使用Python中的getattr()和setattr()函数来访问对象的属性。getattr()函数用于获取对象的属性值,而setattr()函数用于设置对象的属性值。例如:
1 | ## 获取对象的属性值 |
3.20.12 type函数
在Python中,type()
函数用于获取对象的类型。它可以接受一个对象作为参数,并返回该对象的类型。
例如,如果我们有一个字符串变量s
,我们可以使用type()
函数来获取它的类型:
1 | s = "Hello, World!" |
type()函数返回一个类型对象,它表示对象的类型。在上面的例子中,
<class ‘str’>`表示字符串的类型。
除了获取对象的类型,type()
函数还可以用于创建自定义类型的对象。我们可以定义一个类,并在其中使用type()
函数来创建该类的实例。例如:
1 | class MyClass: |
在这个例子中,我们定义了一个名为MyClass
的类,并在其中定义了一个value
属性。然后,我们使用type()
函数创建了一个名为MyInstance
的类,并使用该类创建了一个实例。最后,我们打印了该实例,得到了MyClass(42)
的结果。
3.20.13 元类
Python中的元类(metaclass)是一种特殊的类,它可以用来创建其他的类。元类是类的类,即元类的实例是类。通过定义元类,您可以控制类的创建过程,并在创建类时对其进行修改。
元类的主要作用是定义类的属性和行为。您可以使用元类来控制类的属性和方法的创建、修改和删除。元类还可以定义类的构造函数、类方法、静态方法、属性等。
在Python中,可以通过设置__metaclass__
属性来指定一个类的元类。如果一个类没有显式地指定元类,则使用内置的type
函数作为其元类。
以下是一个简单的元类示例:
1 | class MyMeta(type): |
在这个例子中,我们定义了一个名为MyMeta
的元类,它继承自内置的type
类。在MyMeta
的__new__
方法中,我们为新创建的类添加了一个名为my_attribute
的属性。然后,我们使用MyMeta
作为MyClass
的元类。最后,我们打印出MyClass.my_attribute
,它应该输出Hello, world!
。
3.20.14 抽象基类
Python中的抽象基类(Abstract Base Class,简称ABC)是指定义了纯虚成员函数的类,它只提供了接口,并没有具体实现。
抽象基类不能被实例化,通常是作为基类供子类继承,子类中重写虚函数,实现具体的接口。子类必须实现抽象基类的方法,否则无法实例化。
当我们需要创建一个类,并希望它的子类必须实现某些方法时,可以使用抽象基类。下面是一个抽象基类的例子:
1 | from abc import ABC, abstractmethod |
在这个例子中,Animal
是一个抽象基类,它定义了一个抽象方法speak()
。这意味着Animal
类本身不能被实例化,只有它的子类可以被实例化。同时,Dog
和Cat
是Animal
的两个子类,它们都必须实现speak()
方法。如果我们试图实例化Animal
类本身,Python会抛出一个TypeError异常。
3.21 模块和包
Python中的模块和包是Python代码组织的基本单元,是Python程序的基础组成部分。
在Python中,一个文件(以“.py”为后缀名的文件)就叫做一个模块,每一个模块在python里都被看做是一个独立的文件。Python中的模块可分为三类,分别是内置模块、第三方模块和自定义模块。内置模块是Python中自带的模块;第三方模块是由非官方制作发布的、供给大众使用的Python模块等等。
包(Package)是包含模块文件的目录,目录名称就是包名称,目录中可以包含目录,子目录也是包,但包名称应该包含上一级目录的名称。Python引入了按目录来组织模块是为了避免模块名冲突,不同包中的模块名可以相同。
模块和包的导入可以通过import
语句实现。import
语句允许你使用Python代码来访问其他Python模块中的函数、类和变量等。
导入模块的基本语法如下:
1 | import module_name |
上述语法将module_name
模块导入当前命名空间,可以在代码中使用module_name.function_name
或module_name.class_name
等方式来访问该模块中的函数、类等。
如果要使用模块中的短名称(即不包含模块名的名称)来访问模块中的内容,可以使用以下语法:
1 | from module_name import function_name, class_name, ... |
上述语法将function_name
、class_name
等导入当前命名空间,可以直接使用这些短名称来访问它们。
如果想要一次性导入一个模块中的所有内容,可以使用以下语法:
1 | from module_name import * |
上述语法将模块中的所有内容导入当前命名空间,可以直接使用这些内容。但是,不建议过多使用这种方式导入,因为这会导致命名空间污染。
对于包的导入,可以使用以下语法:
1 | import package_name.module_name |
上述语法将package_name
包中的module_name
模块导入当前命名空间,可以直接使用它们。如果要使用包的短名称来访问其中的内容,可以使用以下语法:
1 | from package_name import function_name, class_name, ... |
上述语法将包中的function_name
、class_name
等导入当前命名空间,可以直接使用这些短名称来访问它们。