七、Python基础(异常、模块、文件操作)
目录:
一、异常
1.抛出异常
在程序运行过程中,如果Python解释器遇到一个错误(不一定在解释前就识别出错误),就会停止执行程序,并且会提示一些错误信息,这就是异常
程序停止执行并且提示错误信息,这个动作我们称为抛出异常
2.简单的捕获异常语法
简单的捕获异常的代码结果如图所示:
即如果能够正常执行 try 中的代码,则会跳过 except 来执行后续的代码;如果执行 try 时出现异常,就会执行 except 中的代码
例:
try:
num = int(input("请输入一个整数:"))
except:
print("输入错误")
3.错误类型的捕获
一般来说,我们并不像上述情况这样用同一手段来处理错误,我们可能会针对不同的出错情况来进行不同的处理
错误类型的捕获代码结构如图所示:
当Python解释器抛出异常时,最后一行错误信息的第一个单词就是错误类型
例:
num = int(input("请输入一个整数:"))
result = 10 / num
错误类型:ValueError
错误类型:ZeroDivisionError
例(错误类型的捕获):
try:
num = int(input("请输入一个整数:"))
result = 10 / num
except ValueError:
print("出现了数据类型异常")
except ZeroDivisionError:
print("出现了除零异常")
except Exception as result:
print("出现了未知错误")
提示:由于可能存在无法提前预知的错误类型,因此可以使用 except Exception as result: 来捕获未知的错误类型,并进行相应的处理
4.异常捕获的完整语法
异常捕获的完整代码结构如图所示:
例:
try:
num = int(input("请输入一个整数:"))
result = 10 / num
except (ValueError, ZeroDivisionError):
print("出现了数据类型异常或除零异常")
except Exception as result:
print("出现了其他类型的异常")
else:
print("没有出现异常")
finally:
print("必然执行")
5.异常的传递
异常的传递——当函数/方法执行出现异常时,会将异常传递给函数/方法的调用一方
如果传递到主程序,仍然没有异常处理,程序才会被终止
- 在开发中,可以在主函数中增加异常捕获
- 而在主函数中调用的其他函数,只要出现异常,都会传递到主函数的异常捕获中
- 这样就不需要在代码中,增加大量的异常捕获,能够保证代码的整洁
例:
def function1():
num = int(input("请输入一个整数:"))
return num
def function2(temp):
result = 10 / temp
return result
try:
function2(function1())
except (ValueError, ZeroDivisionError):
print("出现了数据类型异常或除零异常")
except Exception as result:
print("出现了其他类型的异常")
else:
print("没有出现异常")
6.raise 主动抛出异常
在开发中,除了代码执行出错时Python解释器会抛出异常之外,还可以根据应用程序特有的业务需求主动抛出异常
示例(图摘自黑马程序员):
- 提示用户输入密码,如果密码长度小于8,抛出异常
注: - 当前函数只负责提示用户输入密码,如果密码长度不正确,需要其他的函数进行额外处理
- 因此可以抛出异常,由其他需要处理的函数捕获异常
主动抛出异常:
- Python中提供了一个 Exception 异常类
- 在开发中,如果满足特定业务需求时,希望抛出异常,可以:
创建一个 Exception 的对象
使用 raise关键字 抛出异常对象
例:
def input_password():
"""提示用户输入密码"""
password = input("请输入密码:")
"""判断密码长度"""
if len(password) >= 8:
return password
else:
"""创建异常对象Exception"""
PasswordError = Exception("密码为:%s,密码过短,密码长度应大于或等于8" % password)
"""主动抛出异常"""
raise PasswordError
try:
input_password()
except Exception as result:
# 打印异常信息
print(result)
二、模块
1.模块的基本概念
模块是Python程序架构的一个核心概念
- 每一个以扩展名 .py 结尾的Python源代码文件都可以是一个模块
- 模块名同样也是一个标识符,需要符合标识符的命名规则——即必须由字母、数字和下划线组成,其次不能以数字为开头
- 在模块中定义的全局变量、函数、类都是提供给外界直接使用的工具
- 模块就好比是工具包,要想使用这个工具包中的工具,就需要先导入这个模块
导入模块的代码结构如图所示:
(1)方式1(不推荐使用,不符合Python的代码规范)
(2)方式2(推荐使用)
模块名.函数/方法/类等
访问或使用模块中的内容
2.为模块设置别名
import 模块名 as 别名
导入模块,同时为模块设置别名
- 如果模块名过长,设置别名可以方便后续代码的编写
- 类似于C语言的 typedef 关键字,其目的可以是设置别名,方便后续代码的编写或记忆
- 模块别名应符合大驼峰命名法
3.from import 部分导入
from 模块名 import 工具名
从模块中导入指定工具
-
导入后无需跳过 模块名. 即可直接通过函数名/方法名/类名等直接使用这些工具
-
如果两个模块,存在同名的函数/方法/类等,那么后导入模块的工具,会覆盖掉先导入的模块的工具
因此:
- 开发时 import 代码应该统一写在代码的顶部,更容易及时发现冲突
- 一旦发现冲突,可以使用 as关键字 给其中一个重名工具起一个别名
from 模块名 import *
导入模块中的所有工具
- 这种方式了解一下即可,不推荐使用,因为函数重名并没有任何的提示,出现问题不好排查
4.模块的搜索顺序[扩展]
Python的解释器在导入模块时,将:
- 搜索当前目录下指定模块名的文件,如果有则直接导入
- 如果没有,则搜索系统目录
在开发中,给文件命名时应注意不要与系统的模块文件重名,Python中每一个模块都有一个内置属性 __file__ 可以查看模块的完整路径
例:
import random
print(random.__file__)
5. __name__ 属性
在导入文件时,被导入文件中的所有代码都会被执行一遍,因此如果被导入文件内如果除了定义的函数/方法/类之外,还有主函数,那么主函数是会被执行的
实际开发场景:
- 在实际开发中,每一个模块都是独立开发的,大多都有专人负责
- 开发人员通常会在模块下方增加一些测试代码,这些测试代码一般仅在模块内使用,不想被导入到其他文件中执行
此时,就需要用 __name__ 属性 来进行处理了
__name__ 属性:
- __name__ 属性可以做到测试模块的代码只在测试情况下被执行,而在被导入时不会被执行
- __name__ 是Python的一个内置属性,记录着一个字符串
- 如果是被其他文件导入的, __name__ 是模块名
- 如果是当前执行的程序, __name__ 是 __main__
- 即在不同的文件中,__name__ 字符串的值会发生不同的变化
演示:
(1) 在当前文件( function_file )中, __name__ 的值为: __main__
print(__name__)
(2) 当其他文件导入 function_file 时, __name__ 的值为: 模块名
function_file 中的代码:
print(__name__)
其他文件中的代码:
import function_file
于是,我们可以通过判断 __name__ 中的值来判断当前在哪个文件中执行模块中的代码,如果 __name__ 的值是 __main__ ,那么当前是在模块文件中执行模块中的代码(测试代码),如果 __name__ 的值是 模块名 ,那么当前是在其他文件中执行模块中的代码
例:
if __name__ == "__main__":
print(__name__)
print("正在执行测试代码")
当前在模块文件下执行,因此能够被执行
因此我们在阅读别人的模块时,经常能够看见如下的结构:
6. Python中的包
- 包是一个包含多个模块的特殊目录
- 目录下有一个特殊的文件 __init__.py
- 包名的命名方式和变量名一致,由小写字母和下划线组成
- 使用 import 包名 可以一次性导入包中的所有模块
import 包名
导入包中所有的模块
7. PyCharm下创建Python包
创建一个Python包十分简单,要进行以下步骤:
(1)新建Python包目录,并添加 __init__.py 文件
- 方法1
首先创建一个新目录,目录名就是包名:
在包目录中创建一个 __init__.py 的Python文件,这个文件是Python包必须有的文件
- 方法2
在Python工程主目录下选择新建Python包的同时自动生成 __init__.py 文件
(2)添加模块
在Python包目录中自学添加 .py 模块文件即可
(3)添加 __init__.py 文件配置
配置方式如图所示,在 __init__.py 文件中,添加如下内容:
例:
- 在工程目录下新建一个 message 包(包含 __init__.py 文件)
- 在包目录下,新建两个文件 send_message 和 receive_message
- 在 send_message 文件中定义一个 send 函数
- 在 receive_message 文件中定义一个 receive 函数
- 在外部直接导入 message 的包
(1)__init__.py 文件:
from . import send_message
from . import receive_message
(2)send_message 文件:
def send(temp):
print("正在发送%s......" % temp)
(3)receive_message 文件:
def receive():
return "这是来自未来的短信"
从外部文件中导入并使用 message 包:
"""导入模块"""
import message.send_message
import message.receive_message
message.send_message.send("Hello World")
print(message.receive_message.receive())
*8.发布模块(了解)
制作发布压缩包步骤:
(1)创建 setup.py 文件,文件中包含以下信息:
from distutils.core import setup
setup(name="package", # 包名
version="1.0", # 版本
description="这个包是......包", # 简单描述信息
long_description="这个包主要用于", # 详细描述信息
author="~宪宪", # 作者
author_email="123456789@qq.com", # 作者邮箱
url="www.https://blog.csdn.net/weixin_48261286?spm=1000.2115.3001.5343.com", # 主页
py_modules=["package.module1", # 包中包含的模块名列表
"package.module2",
"package.module3"])
- 因为上述是调用 setup(**kwargs) 函数,因此字典格式是 = 符号
- 这个文件并不能直接通过 PyCharm 执行,可以通过 Ubuntu 终端执行
(2)构建模块,在Ubuntu终端中,输入以下指令:
python3 setup.py build
- 终端会自动构建 build 文件,可以通过 tree 查看文件结构
(3)生成发布压缩包,在Ubuntu终端中,输入以下指令:
python3 setup.py sdist
- 终端会自动构建 .tar.gz 压缩包文件
安装模块步骤:
(1)解压压缩包文件
tar -zxvf < package.tar.gz >
package.tar.gz 要解压的压缩包文件
(2)向解释器安装Python包
sudo python3 setup.py install
- 可以是其他解释器,这里演示的是向 python3解释器 安装Python包
卸载模块步骤:
直接从安装目录下,把安装好的Python包的目录删除即可
cd /usr/local/lib/python3.5/dist-packages/
- 安装好的Python包放在上述路径下
sudo rm -r < package >*
< package > 即已安装的Python包名
< package >* 即所有以 < package > 为前缀的文件
9.pip 安装第三方模块
第三方模块通常是指由知名的第三方团队开发的并且被程序员广泛使用的 Python包/模块,如: pygame 就是一套非常成熟的游戏开发模块,在后续中,我们将需要用到这个模块来进行飞机大战的开发
下面演示在 Linux 环境下利用 pip 进行 pygame 的安装和卸载的命令(Windows环境下pip的安装百度即可)
将模块安装到 Python2.X 环境:
sudo pip install pygame
sudo pip uninstall pygame
将模块安装到 Python3.X 环境:
sudo pip3 install pygame
sudo pip3 uninstall pygame
三、文件操作
常用的保存方式:文本文件和二进制文件
1.操作文件的一般步骤
- 打开文件
- 读、写文件
读 将文件内容读入内存
写 将内存内容写入文件 - 关闭文件
2.操作文件的函数/方法
序号 | 函数/方法 | 含义 |
---|---|---|
1 | open(file, mode) | 打开文件,并且返回文件操作对象,mode 为访问方式 |
2 | read | 将文件内容读取到内存 |
3 | readline | 按行读取文件的内容 |
4 | write(str) | 方法,将 str 中的内容读写入文件,str 可以是 read/readline 的返回值 |
5 | close | 关闭文件 |
- read/write/close 三个方法都需要通过文件对象来进行调用
3.open 打开文件
- open函数的第一个参数是要打开的文件名(文件名是字符串,并且区分大小写)
- 如果文件存在,则返回文件操作对象
- 如果文件不存在,则抛出异常
访问方式 mode | 含义 |
---|---|
r | 以只读的方式打开文件,文件指针将会置于文件的开头,这是默认模式,如果文件不存在则抛出异常 |
w | 以只写的方式打开文件,如果文件已存在则覆盖原文件;如果文件不存在则创建新文件再写入文件 |
a | 以追加的方式打开文件,如果该文件已存在,文件指针将会置于文件的结尾,如果文件不存在则创建新文件再写入文件 |
r+ | 以读写的方式打开文件,文件指针将会置于文件的开头,如果文件不存在则抛出异常 |
w+ | 以读写的方式打开文件,如果文件已存在则覆盖原文件;如果文件不存在则创建新文件再写入文件 |
a+ | 以读写的方式打开文件,如果文件已存在,文件指针将会置于文件的结尾,如果文件不存在则创建新文件再写入文件 |
- 频繁地移动文件指针会降低文件的读写效率,在开发中更多地会使用只读、只写的方式操作文件
- a——append 追加
例:打开名为 Database 的文本文件
"""默认访问方式"""
file = open("Database.txt")
4.read 读取文件
- read 方法可以一次性读取并返回文件的所有内容
例:读取并打印 Database 文本文件中的全部内容
"""打开Database文件"""
file = open("Database.txt")
"""读取内容"""
text = file.read()
print(text)
"""关闭文件"""
file.close()
- 如果忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问
注:
- 由于Windows的文本编辑器的打开编码方式为GBK,因此若想要在Python中 read() 或 readline() 到中文汉字,则需要在 open() 中括号 ( ) 的最后加上 encoding=“UTF-8”,与前面用逗号加空格隔开
例:
如果没有增加 encoding=“UTF-8”:
file = open("Database.txt")
fd = file.read()
print(fd)
增加 encoding=“UTF-8” 后:
file = open("Database.txt", encoding="UTF-8")
fd = file.read()
print(fd)
文件指针:
文件指针标记在文件中读取数据的位置,第一次打开文件时,通常文件指针会指向文件开始的位置,当执行了 read 方法后,文件指针会移动到读取内容的末尾(默认情况下)
len() 函数可以对文件对象中文件指针后续内容的长度进行统计,文件指针前的内容不统计
*文本文件的编码格式(了解):
文本文件存储的内容是基于字符编码的文件,常见的编码有 ASCII 编码,UNICODE 编码等
- python2.X 默认使用 ASCII 编码
- python3.X 默认使用 UTF-8 编码
ASCII 编码表:
UTF-8 编码格式:
- 计算机中使用1~6个字节来标识一个 UTF-8 字符,涵盖了地球上几乎所有地区的文字
- 大多数汉字会使用3个字节表示
- UTF-8 是 UNICODE 编码的一种编码格式
在 python2.X 中使用使用中文:
在 Python2.X 文件的第一行增加以下代码,解释器会以 UTF-8 编码来处理Python文件
# *-* coding:utf8 *-*
- 上述方法是官方推荐使用的
- 也可以使用下述方式
# coding=utf8
- 在 python2.X 中,即使指定了文件使用 UTF-8 的编码格式,但在遍历字符串时,仍然会以字节为单位遍历字符串,而大多数汉字会使用3个字节表示
- 若要能够正确地遍历字符串,在定义字符串时,需要在字符串的引号之前,增加一个小写字母 u ,告诉解释器这是一个 unicode 字符串(使用 UTF-8 编码格式的字符串)
5.readline 单行读取文件
read 方法默认会把文件的所有内容一次性读取到内存中,如果文件太大,对内存的占用会十分严重
readline 方法可以一次读取一行的内容,方法执行后,会把文件指针移动到下一行,准备再次读取
其次,readline 方法也可以通过 while 循环来读取所有内容
例:通过 readline 来读取文件中的所有内容
方法1:
file = open("Database.txt")
while 1:
text = file.readline()
"""判断是否读取到了内容"""
if not text:
break
print(text, end="")
file.close()
方法2:
file = open("Database.txt")
while 1:
text = file.readline()
"""判断是否读取到了内容"""
if len(text) == 0:
break
print(text, end="")
file.close()
- 注:len(text) 能够识别出空行,空行是 \n
6.阶段小结:实现文件复制
file1 = open("Database.txt", "r")
file2 = open("New_Database.txt", "a")
while True:
fd = file1.readline()
if not fd:
break
file2.write(fd)
file1.close()
file2.close()
7.补充:文件/目录的常用管理操作
在 终端/文件浏览器 中可以执行常规的 文件/目录 管理操作,例如:创建、重命名、删除、改变路径、查看目录内容......
在Python中,如果希望通过程序实现上述功能,需要导入 os 操作系统模块
文件操作:
序号 | 方法 | 含义 | 示例 |
---|---|---|---|
1 | rename | 重命名文件 | os.rename(源文件名, 目标文件名) |
2 | remove | 删除文件 | os.remove(文件名) |
目录操作:
序号 | 方法 | 含义 | 示例 |
---|---|---|---|
1 | listdir | 列出目录列表 | os.listdir(目录名) |
2 | mkdir | 创建目录 | os.mkdir(目录名) |
3 | rmdir | 删除目录 | os.rmdir(目录名) |
4 | getcwd | 获取当前目录 | os.getcwd() |
5 | chdir | 修改工作目录 | os.chdir(目标目录) |
6 | path.isdir | 判断是否有文件 | os.path.isdir(文件路径) |
- 文件操作/目录操作都支持相对路径和绝对路径
终端命令:
方法 | 含义 | 示例 |
---|---|---|
system() | 调用终端命令 | os.system(“pause”) |
四、eval 函数
1.eval 函数简介
eval 函数十分强大,它可以将字符串当作有效表达式来求值并返回计算结果
例:
print(eval("1 + 1"))
print(eval("'ab' * 10"))
print(type(eval("[1, 2, 3]")))
print(type(eval("{'name': '张三', 'age': 18}")))
2.案例演示——算式计算器
while 1:
input_str = input("请输入一个算术表达式:")
print(eval(input_str))
注:
- eval() 权限较高,在开发中切勿滥用 eval() 函数,在开发中不要使用 eval() 直接转换 input 结果,因为 input 输入的指令不加限制可能会危害计算机
补充:
__import__('os').system('ls')
等效于:
import os
os.system("终端命令")
例:
在Linux中,若直接把 __import__('os').system('rm abc')
作为 eval() 函数的结果,则可以直接执行删除abc文件 rm abc 的终端命令,显然,这很危险
- 执行成功则返回0
- 执行错误则返回错误信息