Python基础
1.变量
python中变量很简单,不需要指定数据类型,直接使用等号定义就好。python变量里面存的是内存地址,也就是这个值存在内存里面的哪个地方,如果再把这个变量赋值给另一个变量,新的变量通过之前那个变量知道那个变量值的内存地址存起来,而不是指向之前的那个变量。
变量的定义规则:
- 变量名要见名知意,不能用拼音,不能用中文
- 变量名只能是字母,数字,下划线的任意组合
- 变量名的第一个字符不能是数字
以下关键字不能声明为变量名:
2.单引号,双引号和三引号(三个单引号)
python中定义变量的时候字符串都用引号引起来,此时单引号和双引号没有区别。但是如果字符串中有单引号的话,外面就得用双引号;如果里面有双引号,外面就用单引号;如果既有单引号又有双引号,那么用三引号,三引号也可以多行注释代码,单行注释,使用#。
3.数字
- python 中数字类型的变量可以表示任意大的数值
- 十六进制一 0x 开头,八进制以 0o 开头,二进制以 0b 开头
- python 中可以表示复数用j来表示虚部 complex(a,b)函数可以形成复数
- real 查看实部 imag 查看虚部 conjugate()返回共轭复数
a=99999999999999
print(a*a)
print(math.sqrt(3**2+4**2))
a=3+4j
b=complex(5,6)
c=a+b
print(c)
print(c.real)
print(c.imag)
print(c.conjugate())
运行结果
9999999999999800000000000001
5.0
(8+10j)
8.0
10.0
(8-10j)
4.输入,输出
python使用input函数接收用户输入,python2中使用raw_input,接收的是一个字符串;使用print输出:
input 在接收输入的时候,是可以看到你输入的值的,如果是输入密码这样的呢,不想让别人看到你的密码,怎么办呢,就需要用到一个标准库,getpass,什么是标准库呢,就是不需要你再去安装,装完 python 就有的库,就是标准库,getpass 就是一个标准库,导入进来之后,直接使用 getpass.getpass 方法就可以在输入的时候,不会显示了:
注意:pycharm 不支持 getpass 模块,在 python 模块的 ide 下可展示。
5.列表(List)/元组(tuple)
创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可。
与字符串的索引一样,列表索引从0开始。列表可以进行截取、组合等。
#!/usr/bin/python list1 = ['physics', 'chemistry', 1997, 2000]
list2 = [1, 2, 3, 4, 5, 6, 7 ] print "list1[0]: ", list1[0]
print "list2[1:5]: ", list2[1:5]
你可以对列表的数据项进行修改或更新,你也可以使用append()方法来添加列表项,如下所示:
list = [] ## 空列表
list.append('Google') ## 使用 append() 添加元素
list.append('Runoob')
print list
列表对 + 和 * 的操作符与字符串相似。+ 号用于组合列表,* 号用于重复列表。如下所示:
列表常用函数
list = ["111", 222, True, ['I', "LOVE", """YOU"""]]
# 获取指定元素的索引,如果元素不存在则抛出异常
idx = list.index(222)
# 修改指定索引的元素值
list[idx] = 333
# 指定索引插入新元素.insert(索引, 元素)
list.insert(idx, 444)
# 追加元素到尾部
list.append("ME TOO.")
# 追加多个数据到尾部
list.extend([1, 2, 3, 4, 5])
# 删除元素
del list[len(list) - 1] # 仅删除 len(列表)获取列表的大小(元素个数)
delVal = list.pop(idx) # 取出并删除
list.remove(4) # 删除列表中第一个匹配元素
# list.clear() # 清空列表元素
print(list)
# 统计列表内指定元素的个数
num = list.count('111')
print(num)
# 列表遍历 while
idx2 = 0
while idx2 < len(list):
val = list[idx2]
print(f" while idx = {idx2} value = {val}")
idx2 += 1
# 列表遍历 for
for val in list:
print(f" for value = {val}")
# 元组 不可修改的列表
t1 = (1, "hello", True)
t2 = ()
t3 = tuple()
t4 = ("1",) # 定义单个元素的元组后面必须加','
t5 = ((1, 2), 3, ('aaa', "bbb", True))
# 取元素
val = t5[2][1]
print(val)
# 函数
idx = t5.index(3)
num = t5.count(True)
print(idx, num, len(t5))
注:
- 元组内嵌套的list内容是可以修改的
- 字符串是特殊的元组
切片:
语法:序列[起始下标:结束下标:步长] 例:list[:]
起始下标可以为空,为空时表示从索引0开始
结束下标可以为空,为空表示到结尾
步长为取元素的方式,1为逐个取,2为跳过一个取,为负数表示反向取(起始下标和结束下标也要反向)
6.Python列表函数&方法
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
定义一个函数:
你可以定义一个由自己想要功能的函数,以下是简单的规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号**()**。
- 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
语法
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
Python包含以下函数:
- cmp(list1, list2):比较两个列表的元素
- len(list):列表元素个数
- max(list):返回列表元素最大值
- min(list):返回列表元素最小值
- list(seq):将元组转换为列表
Python包含以下方法:
- list.append(obj):在列表末尾添加新的对象
- list.count(obj):统计某个元素在列表中出现的次数
- list.extend(seq):在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
- list.index(obj):从列表中找出某个值第一个匹配项的索引位置
- list.insert(index, obj):将对象插入列表
- [list.pop(index=-1]):移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
- list.remove(obj):移除列表中某个值的第一个匹配项
- list.reverse():反向列表中元素
- list.sort(cmp=None, key=None, reverse=False):对原列表进行排序
7.常用内置函数
执行这个命令可以查看所有内置函数和内置对象(两个下划线)
>>>dir(__builtins__)
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy',
'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
测试:
a=-2
b=[1,2,3,4,0]
c='a'
print( abs(a) ) #返回数字的绝对值
print( all(b) ) #对于可迭代对象所有元素 全部非零返回true 若存在零返回false
print( any(b) ) #对于可迭代对象存在元素非零,则返回true
print( bin(a) ) #把数字转换为二进制串
print( callable(a) ) #测试对象是否可调用,类和函数是可调用的
print( chr(65) ) #返回ASCII编码的字符
#print( dir(a) ) #返回指定对象的成员列表
print( ord(c) ) #返回一个字符的编码
print( str(b) ) #把对象转化为字符串
print( help(math.sin)) #查看指定方法的使用帮助
print( list(b) )# 把对象转换为 列表
print( set(b) ) #集合
print( tuple(b) )# 元组
#print( dict(b) ) #字典并返回
结果:
2
False
True
-0b10
False
A
97
[1, 2, 3, 4, 0]
Help on built-in function sin in module math:
sin(…)
sin(x)
Return the sine of x (measured in radians).
None
[1, 2, 3, 4, 0]
{0, 1, 2, 3, 4}
(1, 2, 3, 4, 0)
8.对象的删除
x=[1,2,3,4,5]
y=3
print(y)
del y
del x[1]
print(x)
print(y)
结果:
3
[1, 3, 4, 5]
Traceback (most recent call last):
File “.../练习.py”, line 11, in
print(y)
NameError: name ‘y’ is not defined
9.模块的导入与使用
python中有大量第三方库可用 “pip3 install 。。。”进行有需要的安装
在使用库函数时,需要导入,有两种方法:
- import 模块名【as 别名】:使用这种方式导入后,需要在使用的对象前加上前缀 “模块名 . 对项名”的方式进行访问,也可以用“别名 . 对象名”的方式使用其中的对象
- from 模块名 import 对象名【as 别名】:使用这种方式仅导入使用的对象,并且可以为这个对象起一个别名,这种方法可以减少查询次数,减少程序员的代码量,不需要使用模块名作为前缀
import math
from math import sin as f print(math.sin(3))
print(f(3))
结果:
0.1411200080598672
0.1411200080598672
比较极端的情况是一次导入模块中全部的对象:
from math import *
不推荐使用这中方法,一旦多个模块中有同名的对象,会导致混乱
10.条件判断
python中条件判断使用if else 来判断,多分支使用if elif…else,也就是如果怎么怎么样就怎么怎么样,否则怎么怎么样,格式如下:
具体代码如下:
11.循环
python中有两种循环,while和for,两种循环的区别是,while循环之前,先判断一次,如果满足条件的话,再循环,for循环的时候必须有一个可迭代的对象,才能循环.python中for循环很简单,循环的是一个可迭代对象中的元素,你这个对象中有多少个元素,就循环多少次,比如说一个数组list,list = [‘a’,’b’,’c’],在别的语言中要想获取到list中所有的值,必须得使用循环取下标这种方式去取数据,就得这样写list[x],list[x],list[x]这样,在Python里面就不需要直接循环就取的是这个list里面的值,循环里面还有两个比较重要的关键字,continue和break,continue的意思是,跳出本次循环,继续进行下一次循环,break的意思是停止循环,也就是说在continue和break下面的代码都是不执行的,格式如下:
12.range()函数
python 的 range() 函数可用来创建一个整数列表,一般用在 for 循环中.
- range()语法:range(start, stop[, step])
- start:计数从start开始,默认是从0开始(闭区间),如:range(5)等价于range(0,5).
- stop:计数到stop结束,但不包括stop(开区间).如:range(0,5)是[0, 1, 2, 3, 4],不包含5.
- step:步长,相邻两个值的差值,默认为1.如:range(0,5)相当于range(0, 5, 1).
13.列表推导式
列表推导式(list comprehension)是指循环创建列表.
# 列表推导式
list_b = [b for b in range(5)]
print(list_b)
上面分别是用for循环和列表推导式创建列表的代码,list_a和list_b的结果是一样的,都是[0, 1, 2, 3, 4].
下面来看复杂点的列表推导式:
# in后面跟其他可迭代对象,如字符串
list_c = [7 * c for c in "python"]
print(list_c) # 带if条件语句的列表推导式
list_d = [d for d in range(6) if d % 2 != 0]
print(list_d) # 多个for循环
list_e = [(e, f * f) for e in range(3) for f in range(5, 15, 5)]
print(list_e) # 嵌套列表推导式,多个并列条件
list_g = [[x for x in range(g - 3, g)] for g in range(22) if g % 3 == 0 and g != 0]
print(list_g)
运行结果:
['ppppppp', 'yyyyyyy', 'ttttttt', 'hhhhhhh', 'ooooooo', 'nnnnnnn']
[1, 3, 5]
[(0, 25), (0, 100), (1, 25), (1, 100), (2, 25), (2, 100)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19, 20]]
代码解释:
- 列表推导式会遍历后面的可迭代对象,然后按照for前的表达式进行运算,生成最终的列表.
- 如果有if条件语句,for遍历后紧跟着进行条件判断.
- 3.如果有多个for循环,则最终的数据数量为多个for循环的笛卡尔积.
- 4.可以进行嵌套的列表推导,与嵌套for循环的原理相同.
14.字典
# 字典定义:
dict_name = { key:value , key:value, ...}
dict_name = {}
dict_name = dict()
# 注:key,value可以为任意类型,key不能为字典
# 取值:
value = dict_name [key]
# 新增/更新元素:
dict_name [key] = value # key存在则更新,不存在则添加
# 删除元素
value = dict_name.pop(key)
# 清空字典
dict_name.clear()
# 获取字典的全部key
keys = dict_name.keys()
# 字典的遍历:方式一
for key in keys:
print(f"{key} {dict_name[key]}")
# 字典的遍历:方式二
for key in dict_name:
print(f"{key} {dict_name[key]}")
# 字典元素统计
num = dict_name.len()
15.集合推导式
# 遍历一个可迭代对象生成集合
set_a = {value for value in '有人云淡风轻,有人负重前行'}
print(set_a)
运行结果:
{'负', '有', '人', '轻', '前', '云', '重', ',', '淡', '风', '行'}
集合是无序且不重复的,所以会自动去掉重复的元素,并且每次运行显示的顺序不一样。
16.五种数据容器总结
my_list = [1,2,3,4,5]
my_tuple = (1,2,3,4,5)
my_str = "abcdefg"
my_set = {1,2,3,4,5}
my_dict = {"key1":1,"key2" : 2 ,"key3":3, "key4":4,"key5",5}
# 容器转列表
list(容器)
# 容器转元组
tuple(容器)
# 容器转字符串
str(容器)
# 容器转集合
set(容器)
# 排序 结果会变成列表输出
sorted(容器) # 升序
sorted(容器,reverse = True) # 降序
17.函数
# 有名称的函数定义(可通过名字重复调用)
def 函数名(a,b,c): # a,b,c为参数可以为任意名称任意数据类型或函数
# 函数体
return a,b # a,b 为返回值,可以为0个或多个
# 匿名函数定义 (只能使用一次)
lambda 参数 : 函数体 (一行代码)
例:
# 定义一个求和/拼接函数
def add(x, y):
return x + y
# 函数做为参数
def test1(add, a, b):
result = add(a, b)
return result
res = test1(add, 1, 2)
print(f"结果是 {res}")
# 使用匿名函数调用
res = test1(lambda a, b: a + b, 3, 4)
print(f"结果是 {res}")
18.文件操作
Python文件的打开、读写、关闭
第一步:打开文件——open()
# 该函数返回一个数据流对象对于对该文件进行读写操作
# name:是要打开的目标文件名的字符串(可以包含文件所在的具体路路径)。 mode:设置打开⽂件的模式(访问模式):只读、写入、追加等
f = open(name,mode)
第二步:从文件中读取/写入数据
# 读数据
f.read(num) # 多用来读取文件的全部数据,num表示要从⽂件中读取的数据的长度(单位是字节),如果没有传入num,那么就表示读取文件中所有的数据
f.readlines() # readlines可以按照⾏的⽅式把整个⽂件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素 如果文件中有换行符,则一并读取出来
f.readline() # 一次读取一行内容。函数每运行一次,文件指针移到下一行为下次读取作准备
# 写数据
f.write('内容') # 每次写入都要覆盖掉之前的内容;若要写入的文件不存在,则新建文件
第二步:关闭文件
f.close() # 关闭⽂文件
下面总结一下函数open(name,mode)中参数mode的种类
- 所有以 r 开头的,如果文件不存在,则报错,不会新建文件;文件指针都会放在文件的开头;
- 所有以 w 开头的,如果文件不存在,则自动创建;文件指针都会放在文件的开头;每次执行该函数时会覆盖掉源文件
- 所有以 a 开头的,如果文件不存在,则自动创建;文件指针会放在文件的末尾用于附加数据,不会覆盖数据
改变文件指针——seek()函数
改变文件的指针,方便更加灵活的读取操作
⽂件对象.seek(偏移量量, 起始位置)
偏移量:移动的步长
起始位置:
0:文件开头
1:当前位置
2:文件结尾
文件名字符串的一些注意事项
“ / “左倾斜是正斜杠,” \ “右倾斜是反斜杠,可以记为:除号是正斜杠一般来说对于目录分隔符,Unix和Web用正斜杠/,Windows一般用反斜杠,具体如下:
Python文件与文件夹操作(os包)
在Python中文件和文件夹的操作要借助os模块里面的相关功能,为什么是os模块,因为操作系统管理着文件系统,文件系统管理着文件(Python3.6以下常用,3.6之后使用pathlib.Path多一点)
文件自身操作
文件重命名
import os
# src:文件当前的路径 dst:要修改成什么样
os.rename(src,dst)
删除文件
#可能会出现要删除的文件找不到的错误
os.remove(src)
文件夹相关操作
创建文件夹
import os
# 当文件夹已存在时,再去创建同名的文件夹会出错
os.mkdir(src)
删除文件夹
import os
os.rmdir(src)
获取当前目录路径
# getcwd为 get current work directory,表示获取当前工作路径
os.getcwd()
改变默认目录
# 切换当前路径到指定路径,用处不大。比如说你现在文件的路径时a,你需要跑到b路径去操作一些东西,需要用到这个函数
os.chdir()
import os
os.getcwd() # a路径
os.chdir('b路径')
os.getcwd() # b路径
获取目录列表
# 获取当前文件所处的文件夹下的所有文件,以列表形式返回
os.listdir()
文件夹重命名
os.rename(src,dst)
图像读取
scikit-image
from skimage import io
img = io.imread('testimg.tif')
import numpy as np
data=np.random.random([100,100])
io.imsave('rand_data.tif',np.float32(data))
PIL库(PILLOW) & imageio
import numpy as np
import imageio
from PIL import Image #PIL pakage name is Pillow
img=imageio.imread(r'G:\leopard.jpg')
high,width,ichannel=img.shape
print(type(img))
print(img.shape)
imageio.imwrite(r'G:\leopard_i1.jpg',img)
imageio.imwrite(r'G:\leopard_i2.jpg',np.float32(img/10)) # automatic brightness adjust
imageio.imwrite(r'G:\leopard_i3.jpg',np.uint8(img/10))
im = Image.open(r'G:\leopard.jpg')
print(type(im))
in_data = np.asarray(im, dtype=np.uint8)
print(type(in_data))
print(in_data.shape)
new_im = Image.fromarray(in_data) # np.uint8, or TypeError: Cannot handle this data type
# new_im.show()
new_im.save(r'G:\leopard_p1.jpg')
19.异常
异常机制是衡量一个编程语言是否成熟的标准之一,使用异常处理机制的python程序容错性会更好。
什么是异常?
在自动化脚本开发程中,往往会出现一些不可预知的错误,这种情况在编程语言中叫做异常。遇到异常,我们要处理它,不是等到异常发生的时候,让IDE帮你处理,等他给你抛出异常的时候,就晚了。当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。
因此需要我们在可能发生异常的地方,主动使用try/except语句。来检测try语句块中的错误,从而让except语句捕获异常信息并处理。
python的异常机制主要依赖try、except、else、finally和raise五个关键字,其中在try关键字后缩进的代码块简称try块,它里面放置的是可能引发异常的代码
在except之后对应的是异常类型和一个代码块,用于表明该except块处理这种类型的代码块;在多个except块之后可以放一个else块,表明程序不出现异常时还要继续执行else块;最后还可以跟一个finally块,finally块用于回收在try块里打开的物理资源,异常机制会保证finally块总被执行;而raise用于引发一个实际的异常,raise可以单独作为一个语句使用,引发一个具体的异常对象。
Python内置异常
内置异常类的层次结构如下:
BaseException # 所有异常的基类
+– SystemExit # 解释器请求退出
+– KeyboardInterrupt # 用户中断执行(通常是输入^C)
+– GeneratorExit # 生成器(generator)发生异常来通知退出
+– Exception # 常规异常的基类
+– StopIteration # 迭代器没有更多的值
+– StopAsyncIteration # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代
+– ArithmeticError # 各种算术错误引发的内置异常的基类
| +– FloatingPointError # 浮点计算错误
| +– OverflowError # 数值运算结果太大无法表示
| +– ZeroDivisionError # 除(或取模)零 (所有数据类型)
+– AssertionError # 当assert语句失败时引发
+– AttributeError # 属性引用或赋值失败
+– BufferError # 无法执行与缓冲区相关的操作时引发
+– EOFError # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发
+– ImportError # 导入模块/对象失败
| +– ModuleNotFoundError # 无法找到模块或在在sys.modules中找到None
+– LookupError # 映射或序列上使用的键或索引无效时引发的异常的基类
| +– IndexError # 序列中没有此索引(index)
| +– KeyError # 映射中没有这个键
+– MemoryError # 内存溢出错误(对于Python 解释器不是致命的)
+– NameError # 未声明/初始化对象 (没有属性)
| +– UnboundLocalError # 访问未初始化的本地变量
+– OSError # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类
| +– BlockingIOError # 操作将阻塞对象(e.g. socket)设置为非阻塞操作
| +– ChildProcessError # 在子进程上的操作失败
| +– ConnectionError # 与连接相关的异常的基类
| | +– BrokenPipeError # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入
| | +– ConnectionAbortedError # 连接尝试被对等方中止
| | +– ConnectionRefusedError # 连接尝试被对等方拒绝
| | +– ConnectionResetError # 连接由对等方重置
| +– FileExistsError # 创建已存在的文件或目录
| +– FileNotFoundError # 请求不存在的文件或目录
| +– InterruptedError # 系统调用被输入信号中断
| +– IsADirectoryError # 在目录上请求文件操作(例如 os.remove())
| +– NotADirectoryError # 在不是目录的事物上请求目录操作(例如 os.listdir())
| +– PermissionError # 尝试在没有足够访问权限的情况下运行操作
| +– ProcessLookupError # 给定进程不存在
| +– TimeoutError # 系统函数在系统级别超时
+– ReferenceError # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象
+– RuntimeError # 在检测到不属于任何其他类别的错误时触发
| +– NotImplementedError # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现
| +– RecursionError # 解释器检测到超出最大递归深度
+– SyntaxError # Python 语法错误
| +– IndentationError # 缩进错误
| +– TabError # Tab和空格混用
+– SystemError # 解释器发现内部错误
+– TypeError # 操作或函数应用于不适当类型的对象
+– ValueError # 操作或函数接收到具有正确类型但值不合适的参数
| +– UnicodeError # 发生与Unicode相关的编码或解码错误
| +– UnicodeDecodeError # Unicode解码错误
| +– UnicodeEncodeError # Unicode编码错误
| +– UnicodeTranslateError # Unicode转码错误
+– Warning # 警告的基类
+– DeprecationWarning # 有关已弃用功能的警告的基类
+– PendingDeprecationWarning # 有关不推荐使用功能的警告的基类
+– RuntimeWarning # 有关可疑的运行时行为的警告的基类
+– SyntaxWarning # 关于可疑语法警告的基类
+– UserWarning # 用户代码生成警告的基类
+– FutureWarning # 有关已弃用功能的警告的基类
+– ImportWarning # 关于模块导入时可能出错的警告的基类
+– UnicodeWarning # 与Unicode相关的警告的基类
+– BytesWarning # 与bytes和bytearray相关的警告的基类
+– ResourceWarning # 与资源使用相关的警告的基类。被默认警告过滤器忽略。
异常处理机制
python的异常处理机制可以让程序具有极其好的容错性。当程序运行出现意外情况时,系统会自动生成一个error对象来通知程序
使用try…except捕获异常
语法结构:
try:
#业务实现代码
...
except (Error1,Error2,...) as e:
alert 输入不合适
goto retry
如果在执行try块里的业务逻辑代码时出现异常,系统自动生成一个异常对象,该异常对象被提交给python解释器,这个过程被称为引发异常。
当Python解释器收到异常对象时,会寻找能处理异常对象的except块,如果找到合适的except块,则把该异常交给该except块处理,这个过程被称为捕获异常。
如果python解释器找不到捕获异常的except块,则运行时环境终止,python解释器也将退出
不管程序代码块是否处于try块中,甚至包括except块中的代码,只要执行该代码块时出现异常,系统总会自动生成一个Error对象。如果程序没有为这段代码定义任何的except块,则python解释器无法找到处理该异常的except块,程序就在此退出,并抛出错误
try 语句按照如下方式工作:
首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)。
如果没有异常发生,忽略 except 子句,try 子句执行后结束。
如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。
如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。
异常类的继承体系
python中try块后面可以有多个except块,目的是为了针对不同的异常类提供不同的异常处理方式。当程序发生不同的意外情况时,系统会生成不同的异常对象,python解释器就会根据该异常对象所属的异常类来决定使用哪个except块来处理该异常
实例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys
try:
a = int(sys.argv[1])
b = int(sys.argv[2])
c = a / b
print("您输入的两个数相除的结果是:",c)
except IndexError:
print("索引错误,运行程序时输入的参数个数不够")
except ValueError:
print("数值错误:程序只能接收整数参数")
except ArithmeticError:
print("算术错误")
except Excepction:
print("未知错误")
实例中导入了sys模块,并通过sys模块的argv列表来获取运行python程序时提供的参数,其中sys.argv[0]通常代表正在运行的python程序名,sys.argv[1]代表运行程序的所提供的第一个参数,sys.argv[2]代表运行程序的所提供的第二个参数,。。。以此类推。
多异常捕获
当捕获多个异常时,可以把要捕获的异常的名字,放到except 后,并使用元组的方式仅进行存储
在使用一个except块捕获多种类型的异常时,只要将多个异常类用圆括号扩起来,中间用逗号隔开即可(也就是构建多个异常类的元组)
实例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys
try:
a = int(sys.argv[1])
b = int(sys.argv[2])
c = a / b
print("您输入的两个数相除的结果是:",c)
Except (IndexError,ValueError,ArithmeticError):
print("程序发生了数组越界、数字格式异常、算术异常之一")
except Excepction:
print("未知错误")
Except (IndexError,ValueError,ArithmeticError)这里来指定了所捕获的异常类型,也就是表明了这个except可以同时捕获三种类型的异常
访问异常信息
如果程序需要在except块中访问异常对象的相关信息,则可以通过为异常对象声明变量来实现。当python解释器决定调用某个except块来处理该异常对象时,会将异常对象赋值给except块后面的异常变量,程序就可以通过这个变量来获得异常对象的相关信息。
所有的异常对象都包含了以下几个常用的属性和方法:
1、args:该属性返回异常的错误编号和描述字符串
2、errno:该属性返回异常的错误编号
3、strerror:该属性返回异常的描述字符串
4、with_traceback(): 通过该方法可以处理异常的传播轨迹信息
实例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def foo():
try:
fis = open("a.txt");
except Exception as e:
#访问异常的错误编号和详细信息
print(e.args)
#访问异常的错误编号
print(e.errno)
#访问异常的详情信息
print(e.strerror)
foo()
运行结果:
(2, 'No such file or directory')
2
No such file or directory
如果要访问异常对象,只要在单个异常类或者异常元组(多异常捕获)之后使用as再加上异常扮靓即可
解析:
该程序调用了Exception对象的args属性(该属性其实就相当于同时返回了errno和strerror这两个属性)访问异常的错误编号和详情信息
else块
在python异常处理流程中还可以添加一个else块,当try块没有出现异常时,程序会执行else块。
try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。
else 子句将在 try 子句没有发生任何异常的时候执行。
try…except语法声明格式:
try:
<语句> #运行别的代码
except <名字>:
<语句> #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句> #如果引发了'name'异常,获得附加的数据
else:
<语句> #如果没有异常发生
实例1:
打开一个文件,在该文件中的内容写入内容,且并未发生异常
#!/usr/bin/python
# -*- coding: UTF-8 -*-
try:
fh = open("testfile", "w")
fh.write("这是一个测试文件,用于测试异常!!")
except IOError:
print "Error: 没有找到文件或读取文件失败"
else:
print "内容写入文件成功"
fh.close()
结果:
$ python test.py
内容写入文件成功
$ cat testfile # 查看写入的内容
这是一个测试文件,用于测试异常!!
实例2:
打开一个文件,在该文件中的内容写入内容,但文件没有写入权限,发生了异常
#!/usr/bin/python
# -*- coding: UTF-8 -*-
try:
fh = open("testfile", "w")
fh.write("这是一个测试文件,用于测试异常!!")
except IOError:
print "Error: 没有找到文件或读取文件失败"
else:
print "内容写入文件成功"
fh.close()
结果:
$ python test.py
Error: 没有找到文件或读取文件失败
使用 else 子句比把所有的语句都放在 try 子句里面要好,这样可以避免一些意想不到,而 except 又无法捕获的异常。
异常处理并不仅仅处理那些直接发生在 try 子句中的异常,而且还能处理子句中调用的函数(甚至间接调用的函数)里抛出的异常
实例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
s = input('请输入除数:')
try:
result = 20 / int(s)
print('20除以%s的结果是:%g' %(s,result))
except ValueError:
print('值错误,您必须输入数值')
except ArithmeticError:
print('算术错误,您不能输入0')
else:
print('没有出现异常')
运行结果:
请输入除数:a
值错误,您必须输入数值
请输入除数:0
算术错误,您不能输入0
请输入除数:5
20除以5的结果是:4
没有出现异常
使用finally回收资源
有时候在try块里打开一些物理资源,如数据库连接、网络连接和磁盘文件等,这些资源都必须被显示回收
说到资源回收可能会联想到Python的垃圾回收机制,其实还是不一样的,Python的垃圾回收机制不会回收任何物理资源,只能回收堆内存中对象所占用的内存
为了保证一定能回收在try块里打开的物理资源,异常处理机制提供了finally块,不管try块中的代码是否出现异常,也不管哪一个except块被执行,甚至在try块或者except块中被执行了return语句,finally块也总会被执行
即:try-finally 语句无论是否发生异常都将执行最后的代码
语法如下:
try:
#业务实现代码
...
except SubException as e:
#异常处理模块1
...
except SubException2 as e:
#异常处理模块2
...
...
else:
#正常处理块
...
finally:
#资源回收块
...
python总会执行finally子句,无论try子句执行时是否发一异常。
如果没有发生异常,python运行try子句,然后是finally子句,然后继续。
如果在try子句发生了异常,python就会回来执行finally子句,然后把异常递交给上层try,控制流不会通过整个try语句。当你想无论是否发生异常都确保执行某些代码时,try/finally是有用的。
实例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
try:
msg = input(">>")
print(int(msg))
except Exception as e:
print("异常的类型是:%s"%type(e))
print("异常的内容是:%s"%e)
else:
print('如果代码块不抛出异常会执行此行代码!')
finally:
print('不管代码块是否抛出异常都会执行此行代码!')
运行结果1:
1
如果代码块不抛出异常会执行此行代码!
不管代码块是否抛出异常都会执行此行代码!
运行结果2:
2
如果代码块不抛出异常会执行此行代码!
不管代码块是否抛出异常都会执行此行代码!
在异常处理语法结构中,只有try块是必需的,也就是说,如果没有try块则不能有后面的except块和finally块,except块和finally块都是可选的,但except块和finally块至少出现其中的一个,也可以同时出现,可以有多个except块,但捕获父类异常的except块应该位于捕获子类异常的except块之后,不能只有try块,既没有except块,也没有finally快。多个except块必须位于try块后面,finally块必须位于所有的except块的后面
实例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
def test():
fis = None
try:
fis = open("a.txt")
except OSError as e:
print(e.strerror)
#return语句强制方法返回
return
#os.__exit(1)
finally:
#关闭磁盘文件,回收资源
if fis is not None:
try:
#关闭资源
fis.close()
Except OSError as ioe:
print(ioe.strerror)
print("执行finally块里的资源回收!")
test()
在通常情况下,一旦在方法里执行到return语句,程序将立即结束该方法,现在不会了,虽然return语句也强制方法结束,但一定会先执行finally块的代码
除非在try块、except块中调用了退出python解释器的方法,否则不管在try块还是在except块中执行代码,或者执行怎么样的代码,出现怎么样的情况,异常处理的finally块总会被执行。调用sys.exit()方法退出程序不能阻止finally块的执行,这是因为sys.exit()方法本身就是通过引发SystemExit异常来退出程序的。
不要在finally块中使用return或者raise等导致中止的语句,一旦在finally块中使用了return或者raise语句,将会导致try块、except块中的return、raise语句失效
实例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def test():
try:
#因为finally块中包含了return语句
#所以下面的return语句失去作用
return True
finally:
return False
a = test()
print(a)
尽量避免在finally块中使用return或者raise等导致方法终止的语句,否则则可能会出现一些奇奇怪怪的错误
20.模块
包和模块
我们可以在一个脚本中定义变量、函数和类,并添加逻辑,但是当某个项目具有复杂的逻辑时,我们希望把这些逻辑分解成不同的脚本,并以一定的合理的方式组织成层级结构,这种具有层级结构的包含脚本的文件夹就称为包。
模块通常指的是定义了变量、函数和类的脚本。但是实际上,包也属于模块的一种,区分一个模块到底是包还是某个具体的脚本,就看该模块是否具有 __ path __ 属性,具有__ path __ 属性的模块称为包,没有 __ path __属性的模块就是我们最长见到的常规脚本。
在python3.3之前,要组成一个包,还必须在顶层目录开始,每一层结构目录中,都必须包含 _ init __ .py文件,但是在python3.3开始,可以没有 __ init __ .py文件。上述中,当我们说包是模块时,我们说的这个包指的就是其目录下的 __ init __ .py初始化文件,这一点,可以通过在 _ init__ .py中打印出__ name __ 属性验证,即 __ init __ .py文件的__ name __属性就是对应的包名。
模块导入
当导入一个模块时,该模块会被执行,当模块是一个包时,根据上述,该包实际上就是该包下的 __ init __ .py文件,所以导入包时,该包对应的 __ init __ .py文件会被执行。当进行类似import A.B.C或者from A.B import C的导入时,会依次执行A、B下的初始化文件,当然如果C依然是一个子包的话,C下的初始化文件也会被执行。
# 导入整个模块
import module_name
math.sqrt(9) #平方根
# 从模块导入特定内容
from module_name import name
from math import pi
# 导入模块内容并重命名
from math import sqrt
sqrt(9)
from cmath import sqrt as csqrt
csqrt(9)
# 以其他名称导入模块
import math as m
m.sqrt(9)
这里需要强调一下import语句和from xxx import yyy语句的一点重要区别,import语句后面跟随的必须是模块,但是from xxx import yyy语句中,yyy不一定是模块,也可以是变量、函数或者类。
21.创建类
使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:
class ClassName:
'类的帮助信息' #类文档字符串
class_suite #类体
类的帮助信息可以通过ClassName.__doc__查看。
class_suite 由类成员,方法,数据属性组成。
实例
以下是一个简单的 Python 类的例子:
#!/usr/bin/python
# -*- coding: UTF-8 -*- class Employee:
'所有员工的基类'
empCount = 0 def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1 def displayCount(self):
print "Total Employee %d" % Employee.empCount def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
- empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。
- 第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
- self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
self代表类的实例,而非类
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
创建实例对象
实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。
以下使用类的名称 Employee 来实例化,并通过 init 方法接收参数。
"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
"创建 Employee 类的第二个对象"
emp2 = Employee("Manni", 5000)
访问属性
您可以使用点号 . 来访问对象的属性。使用如下类的名称访问类变量:
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
执行以上代码输出结果如下:
Name : Zara ,Salary: 2000
Name : Manni ,Salary: 5000
Total Employee 2
你可以添加,删除,修改类的属性,如下所示:
emp1.age = 7 # 添加一个 'age' 属性
emp1.age = 8 # 修改 'age' 属性
del emp1.age # 删除 'age' 属性
你也可以使用以下函数的方式来访问属性:
- getattr(obj, name[, default]) : 访问对象的属性。
- hasattr(obj,name) : 检查是否存在一个属性。
- setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
- delattr(obj, name) : 删除属性。
hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。
getattr(emp1, 'age') # 返回 'age' 属性的值
setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
delattr(emp1, 'age') # 删除属性 'age'