Python从入门到进阶(十)——进阶语法(一)

1 Python列表推导式

列表推导式是Python语言特有的一种语法结构,也可以看成是Python中独特的数据处理方式,它在Python中用于转换和过滤数据.
其语法格式如下所示,其中if条件表达式可省略

[表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]]

注意:学习列表推导式的前提是掌握Python for循环
列表推导式中存在两个名词,一个是 列表,另一个是 推导式 ,列表我们很清楚,就是 Python 的一种数据类型,
而推导式只是一个普通的语法定义词,有的教程里,会将其叫做 解析式,二者是一样的概念。

列表推导式会返回一个列表,因此它适用于所有需要列表的场景。

1.1 怎么用

列表推导式最常见的场景就是优化简单循环.

  • for循环写法
my_list=[1,2,3]
new_list=[]
for i in my_list:
	new_list.append(i*2)
print(new_list)
  • 列表推导式写法
nn_list=[i*2 for i in my_list]
print(nn_list)

是不是对比看就是将 for 循环语句做了变形之后,增加了一个 [],不过需要注意的是,列表推导式最终会将得到的各个结果组成一个新的列表。
再看一下列表推导式语法构成 nn_list = [i2 for i in my_list] ,for 关键字后面就是一个普通的循环,前面的表达式 i2 其中的 i 就是 for 循环中的变量,也就是说表达式可以用后面 for 循环迭代产生的变量,理解这个内容列表推导式就已经掌握 9 成内容了,剩下的是熟练度的问题。

在将 if 语句包含进代码中,运行之后,你也能掌握基本技巧,if 语句是一个判断,其中 i 也是前面循环产生的迭代变量。

nn_list=[i*2 for i in my_list if i>1]
print(nn_list)

1.2 优化两层for循环

这些都是一般技能,列表推导式能支持两层 for 循环,例如下述代码:3

nn_list=[(x,y)for x in range(3) for y in range(3)]
print(nn_list)

当然如果你想,你可以无限套娃下去,列表推导式并没有限制循环层数,多层循环就是一层一层的嵌套,你可以展开一个三层的列表推导式,就都明白了

nn_list=[(x,y,z,m) for x in range(3) for y in range(3) for z in range(3) for m in range(3)]
print(nn_list)

当然在多层列表推导式里面,依旧支持 if 语句,并且 if 后面可以用前面所有迭代产生的变量,不过不建议超过 2 成,超过之后会大幅度降低你代码的可阅读性。

当然如果你希望你代码更加难读,下面的写法都是正确的。

nn_list=[(x,y,z,m)for x in range(3) if x>1 for y in range(3) if y>1 for z in range(3) for m in range(3)]
print(nn_list)
nn_list=[(x,y,z,m)]for x in range(3) for y in range(3) for z in range(3) for m in range(3) if x>1 and y>1]
print(nn_list)
nn_list=[(x,y,z,m)for x in range(3) for y in range(3) for z in range(3) for m in range(3) if
x>1 if y>1]
print(nn_list)

有了两种不同的写法,那咱们必须要对比一下效率,经测试小数据范围影响不大,当循环次数到千万级时候,出现了一些差异。

import time
def demo1():
	new_list=[]
	for i in range(1000000)
		new_list.append(i*2)

def demo2():
	new_list=[i*2 for i in range(1000000)]
s_time=time.perf_counter()
demo2()
e_time=time.perf_counter()
print('代码运行时间:',e_time-s_time)

运行结果

# for 循环
代码运行时间: 1.3431036140000001
# 列表推导式
代码运行时间: 0.9749278849999999

在Python3中列表推导式具备局部作用域,表达式内部的变量和赋值只在局部起作用,表达式的上下文里的同名变量还可以被正常引用,局部变量并不会影响到它们.所以其不会有变量泄露的问题.

x=6
my_var=[x*2 for x in range(3)]
print(my_var)
print(x)

列表推导式还支持嵌套

my_var=[y*4 for y in [x*2 for x in range(3)]]
print(my_var)

1.3 用于转换数据

可以将可迭代对象(一般是列表)中的数据,批量进行转换操作,例如将下述列表所有元素翻两倍

my_list=[1,2,3]

代码如下所示:

my_list=[1,2,3]
new_list=[item*2 for item in my_list]
print(new_list)

掌握上述语法的关键点是item,请重点关注item从my_list遍历而来,并且item*2尾部与for循环存在一个空格

1.4 用于过滤数据

列表表达式,可以将列表中满足条件表达式的值进行筛选过滤,获取目标数据

my_list=[1,2,3]
new_list=[item for item in my_list if item>1]
print(new_list)

掌握上述语法关键是if,其余要点是注意语法编写结构.
接下来你可以尝试将上述编程逻辑,修改为 for 循环语法,学习过程中要着重理解以上两种语法结构可以相互转换,
当你可以无缝将二者进行转换时,该技能你就掌握了。

2 字典推导式

有了列表推导式的概念,字典推导式学起来就非常简单了,语法格式如下:

{:for 迭代变量 in 可迭代对象 [if 条件表达式]}
my_dict={key:value for key in range(3) for value in range(2)}
print(my_dict)

得到的结果如下:

{0:1,1:1,2:1}

此时需要注意的是字典中不能出现同名的key,第二次出现就把第一个值覆盖掉了,所以得到的value都是1
最常见的哪里还是下述的代码,遍历一个具有键值关系的可迭代对象。

my_tuple_list = [('name', '橡皮擦'), ('age', 18),('class', 'no1'), ('like', 'python')]
my_dict = {key: value for key, value in my_tuple_list}
print(my_dict)

3 元组推导式与集合推导式

其实你应该能猜到,在Python中是具备这两种推导式的,而且语法相信你已经掌握了,不过语法虽然差不多,但是元组推导式运行结果却不同.具体如下

my_tuple=(i for i in range(10))
print(my_tuple)

运行结果:

<generator object <genexpr> at 0x0000000001DE45E8>

使用元组推导式生成的结果并不是一个元组,而是一个生成器对象,需要特别注意下,这种写法在有的地方会把它叫做生成器语法,不叫做元组推导式。

集合推导式也有一个需要注意的地方,先看代码:

my_set={value for value in 'HelloWorld'}
print(my_set)

因为集合是无序且不重复的,所以会自动去掉重复的元素,并且每次运行显示的顺序不一样,使用的时候很容易晕掉

4 提高场景

再次查看推导式语法结构中,涉及了一个关键字,叫做 可迭代对象,因为我们可以把自己目前掌握的所有可迭代对象,
都进行一下尝试,例如使用 range() 函数。

my_list = [1, 2, 3]
new_list = [item for item in range(1, 10) if item > 5]
print(new_list)

检验是否掌握,可以回答下述两个问题。

  • 如果可迭代对象是一个字典,你该如何操作?
  • 如果可迭代对象位置使用了 enumerate() 函数,你该如何操作?

除了可迭代对象部分可以扩展知识点, if 表达式 中的 条件表达式 也支持各种布尔运算,如果用中文进行翻译,
表示把满足条件的元素,放置到新的列表中。

5 三元表达式

三元表达式是什么
Python 中没有其它语言的三元表达式(三目运算符)相关说法,但是有类似的语法。
在 Python 中,三元表达式是一种语法结构,一般被 Python 开发者叫做条件表达式,它的结构如下所示:

表达式(1)True 执行语句 if 条件表达式(1) else 表达式(1)False执行语句

5.1 怎么用

  1. 用于if 语句简化
    三元表达式可以将简单的if语句缩减为一行代码
age=20
cn="成年" if age>=18 else "未成年"
print(cn)

原if语句如下所示:

age=20
if age>=18:
	cn="成年"
else:
	cn="未成年"
  1. 返回多条语句
    可以编写如下代码结构,在条件表达式中返回多条语句
age=20
cn="成年","大于18" if age>=18 else "未成年"
print(cn)

代码返回一个元组,内容为 (‘成年’, ‘大于18’) ,这里一定注意不要使用分号 ; ,否则只返回第一个语句的结果。

age=20
cn="成年";"大于18" if age>=18 else "未成年"
print(cn)

运行代码之后,输出成年.

  1. 在函数内部使用三元表达式
    有些简单的判定逻辑,可以直接使用三元表达式简化,例如判断传入参数是否为偶数。
def even_num(num):
	return True if num % 2==0 else False
  1. 三元表达式用于列表推导式
    在列表推导式知识点中,也存在三元表达式的落地应用
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# ret = [i for i in li if i % 2 == 0]
ret = [i if i % 2 == 0 else None for i in li]
print(ret)

重点注意列表生成器部分代码,三元表达式所在位置

  1. 三元表达式与lambda
    有时候可以将三元表达式与lambda进行结合,让代码变得更加简洁
# 声明一个函数,返回较大值
def max(a,b):
	if a>b:
		ret=a
	else:
		ret=b
	return ret

r=max(5,6)
print(r)

由于上述代码非常简单,可以直接使用 lambda 匿名函数实现。

max=lambda a,b:a if a>b else b
r=max(35,32)
print(r)
  1. 提高场景
    Python 条件表达式可以嵌套使用,但是建议最多嵌套两层,而且是在代码简单的情况下,具体编码如下所示,你需要重点学习下述问题。
# 在嵌套的时候,还需要注意if和else配对问题
# 编写一个三元表达式,首先判断其值大于20,然后在判断是奇数
num=19
ret="小于20" if num<20 else ("奇数" if num%2==1 else "偶数")
  1. 扩展知识
  • 元组条件表达式
age=20
cn=("未成年","成年")[age>=18]
print(cn)
  • 字典条件表达式
age=20
cn={False:"未成年",True:"成年"}[age>=18]
print(cn)
  1. 三元表达式的基本使用
  • 1.使用三元表达式统计偶数个数
	def usesy():
        pi=[3,14,15,9,26,5,35,8,97,932]
        even_count=0
        for i in pi:
            # A.
            even_count+=1 if i%2==0 else 0
        assert even_count==4

	if __name__=='__main__':
		usesy()
    1. 使用嵌套的三元表达式统计数字频率,如果是2的倍数加1,如果是4的倍数加2,否则加0
if __name__=='__main__':
	pi=[3,14,15,9,26,5,35,8,97,932]
	even_count=0
	for i in  pi:
		evencount+=2 if i%4==0 else 1 if i%2==0 else 0
	assert even_count=6

6 Python断言

Python 断言,即 Python assert 语句,简单理解就是简易版的 if 语句,
用于判断某个表达式的值,结果为 True,程序运行,否则,程序停止运行,抛出 AssertionError 错误。
语法格式如下所示:

assert 表达式

类比if语句,如下所示:

if not 表达式:
	raise AssertionError

在assert表达式之后,可以增加一个参数[,arguments],等价的if语句如下所示:

if not 表达式:
	raise AssertionError(arguments)

6.1 怎么用

在游戏里面设置一个未满 18 岁禁止访问的功能。

def overage18(age):
    assert age >= 18, "对不起未满18岁,无法进行游戏"
    print("享受欢乐游戏时光")

if __name__ == '__main__':
    overage18(15)

但是这个案例并不是一个完美的案例,因为断言是为了告知 开发人员 ,你写的程序发生异常了。
如果一个潜在错误在程序编写前就能考虑到,例如程序运行时网络中断,这个场景就不需要使用断言。

断言主要为调试辅助而生,为的是程序自检,并不是为了处理错误,程序 BUG 还是要依赖 tryexcept 解决。

由于断言是给 开发人员看的,所以下述案例的断言是有效的。

def something():
	"""该函数执行了很多操作"""
	my_list = [] # 声明了一个空列表
	# do something
	return my_list

def func():
	"""调用 something 函数,基于结果实现某些逻辑"""
	ret = something()
	assert len(ret) == 18, "列表元素数量不对"
	# 完成某些操作

使用断言要注意:
不要用断言验证用户的输入,这是因为 python 通过命令行运行时,如果增加 -O 标识,断言就被全局禁止了,你的所有验证就都丢失了。

6.2 常用断言函数

  • assertEqual(a,b,msg=msg):判断两个值是否相等;
  • assertNotEqual(a,b,msg=msg):上一函数的反义;
  • self.assertTrue(a,msg=none):判断变量是否为 True;
  • assertFalse(a,msg=none):同上反义;
  • assertIsNone(obj=‘’):判断 obj 是否为空;
  • assertIsNotNone(obj=‘’):同上反义;
    还有其它函数,你可以任意检索资料,极容易掌握相关用法。

6.3 Python断言的使用场景

  1. 进行防御性的编程
    我们在使用断言的时候,应该捕捉不应该发生的非法情况。这里要注意非法情况与异常错误之间的区别,
    后者是必然存在的并且是一定要作出处理的。而断言后的条件不一定发生。

  2. 对假定条件做验证
    断言是对程序员的假定做验证,因此这些假定的异常不一定会触发。

6.4 断言的基本使用

所谓断言,就是证明,使用 assert 对输入函数输入参数和函数返回结果分别做前校验和后校验

所谓断言,就是证明,使用 assert 对输入函数输入参数和函数返回结果分别做前校验和后校验

# -*- coding: UTF-8 -*-
def check_param(key_value_map, key):
    '''参数校验,断言就是对输入参数的一个证明,这些参数必须符合这些要求
    key_value_map: 非空字典
    key:非空字符串
    '''
    # TODO(You): 请在此实现校验代码

def get(key_value_map, key):
    check_param(key_value_map, key)
    return key_value_map.get(key)

def set(key_value_map, key, value):
    check_param(key_value_map, key)
    key_value_map[key] = value

if __name__ == '__main__':
    key_value_map = {}
    set(key_value_map, "test", {})
    value = get(key_value_map, "test")
    print("后校验,返回值必须符合预期")
    assert type(value) == type({})
    assert value == {}

请选出下列对函数 check_param 实现错误的选项。
# A.
def check_param(key_value_map, key):
    assert key_value_map
    assert type(key_value_map) == dict
    assert key
    assert type(key) == str
# B.
def check_param(key_value_map, key):
    assert key_value_map is not None and type(key_value_map) == type({})
    assert key is not None and type(key) == type("")
# C.
def check_param(key_value_map, key):
    assert key_value_map is not None
    assert type(key_value_map) == type({})
    assert key is not None
    assert type(key) == type("")
# D.
def check_param(key_value_map, key):
    assert key_value_map is not None
    assert type(key_value_map) == dict
    assert key is not None
    assert type(key) == str

A ❌

7 With…as…

在 Python 中,文件操作,数据库操作,都需要在程序执行完毕进行清理工作,很多时候我们经常忘记手动关闭,因此 Python 集成了一种自动操作,例如文件使用自后,自动释放资源。

上述场景的描述,转换成 Python 语法就是 with…as 语句,即上下文管理器,它在 Python 中实现了自动分配并释放资源。
with…as 语句的语法格式如下:
with 表达式 [as 指定一个变量名]
代码块
代码块
其中[]中的内容可以省略,如果使用表示将前文表达式的结果保存到变量中

7.1 怎么用

  1. 用于文件操作
    with…as… 语句初次接触一般是在文件操作中,如果不使用上下文管理器,对一个文件进行操作的代码如下所示:
file=open("./demo.txt") # 手动打开
data=file.read()
file.close() # 手动关闭

下面是with…as…版本的代码:

with open("./demo.txt") as file:
	data=file.read()

如果不使用上述语句,想要完成一个完善的代码段,需要使用 try…except… 语句进行操作。

file = open("./demo.txt")
try:
    data = file.read()
finally:
    file.close()

7.2 提高场景-with工作原理

接下来通过自己实现一个支持上下文管理器的类,进一步了解 with…as… 的工作原理。

实现原理非常简单,要求在类中实现 enterexit 两个方法即可。

例如我们编写一个动物类 Animal,然后增加上述两个方法。

class Animal:
    def __enter__(self):
        print("__enter__()")

    def __exit__(self, type, value, trace):
        print("__exit__()")


with Animal() as animal:
    pass

你也可以试一下,如果不编写上述两个方法,会出现什么异常。

异常为:AttributeError: __enter__

其中 exit() 方法有 3 个参数,这些参数用于异常处理,参数含义如下所示:

  • type:异常类;
  • value:异常值;
  • trace:调用栈信息。
    当 with…as… 后的代码块抛出异常时,exit() 方法被执行,因此在 with 语法中的 exit 方法中可以处理异常,并且不需要使用 try…except ,如果希望忽略异常,只需要在 exit 方法中返回 True 即可,代码为 return True 。

7.3 with-as语句的使用

  1. JSON文件读写
# JSON文件读写

# -*- coding: UTF-8 -*-
import json

def load_json(file):
    # TODO(You): 实现加载json文件代码

def dump_json(file, obj):
    # TODO(You): 实现将dict写入json文件的代码

if __name__ == '__main__':
    data = {
        'test': 1,
    }
    dump_json('test.json', data)
    load_json('test.json')

# 请选出下列能正确实现这一功能的选项。
# A.
def load_json(file):
    with open(file, 'r') as f:
        return json.loads(f.read())

def dump_json(file, obj):
    with open(file, 'w') as f:
        f.write(json.dumps(obj, 2, False))
# B.
def load_json(file):
    with open(file, 'r') as f:
        return json.loads(f.read())

def dump_json(file, obj):
    with open(file, 'w') as f:
        f.write(json.dumps(obj, indent=2, ensure_ascii=False))
# C.
def load_json(file):
    with open(file, 'w') as f:
        return json.loads(f.read())

def dump_json(file, obj):
    with open(file, 'r') as f:
        f.write(json.dumps(obj, ensure_ascii=False, indent=2))
# D.
def load_json(file):
    with open(file, 'w') as f:
        return json.loads(f.read())

def dump_json(file, obj):
    with open(file, 'r') as f:
        f.write(json.dumps(obj, indent=2, ensure_ascii=False))
# B 正确
  1. 实现一个范围耗时统计类。 实现了 enterexit 成员的类,可以通过 with as 语法使用,程序进入和离开范围的时候会自动调用 enterexit 方法。
实现一个范围耗时统计类。 实现了 __enter__ 和 __exit__ 成员的类,可以通过 with as 语法使用,程序进入和离开范围的时候会自动调用 __enter__ 和 __exit__ 方法。

# -*- coding: UTF-8 -*-
import time

class TimeSpan:
    # TODO(You): 请正确实现计时器的__enter__和__exit成员

if __name__ == '__main__':
    with TimeSpan() as t:
        for i in range(0, 1000):
            print(i)

# 下列哪个实现是错误的?
# A.
class TimeSpan:
    def __enter__(self):
        self.start = time.time()

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end = time.time()
        print('耗时:{}毫秒'.format((self.end-self.start)))
# B.
class TimeSpan:
    def __enter__(self):
        self.end = None
        self.start = time.time()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end = time.time()
        print('耗时:{}毫秒'.format((self.end-self.start)))
# C.
class TimeSpan:
    def __enter__(self):
        self.end = None
        self.start = time.time()

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end = time.time()
        print('耗时:{}毫秒'.format((self.end-self.start)))
# D.
class TimeSpan:
    def __enter__(self):
        return time.time()

    def __exit__(self, exc_type, exc_val, exc_tb):
        end = time.time()
        print('耗时:{}毫秒'.format((end-exc_val)))
# D ❌

8 Python异常捕获

程序异常,就是程序出错了,程序员一般叫做 BUG(八哥),写程序不出错是不可能发生的事情,而程序员要做的事情就是及时的捕获错误,修改错误。

8.1 最常见的错误-除数为0

在数学中也存在类似的问题,除数不可以为 0。相同的概念在编程中也是存在的。

num1=20
num2=0
num3=num1/num2
print(num3)

运行报错:

Traceback (most recent call last):
  File "D:/gun/2/demo7.py", line 3, in <module>
    num3 = num1 / num2
ZeroDivisionError: division by zero

错误内容就是末尾的 ZeroDivisionError: division by zero ,当出现错误程序崩溃,终止运行。错误异常中也提示了错误出现的行数 line 3 在第三行,但查看行号排查错误在很多时候无法直接解决问题,因为出错的地方不在行号那一行,修改 BUG 的效率一般会随着你对 Python 学习的深入逐步增强改善。

8.2 怎么用

  1. try… except语句
    刚才的程序出现错误就终止运行了,如何避免程序被强迫终止,出现问题提示出问题,然后继续运行呢?这就是 try … except 语句使用的场景了。

语法格式:

try:
	可能会出错的代码
except 异常对象:
	处理异常代码

按照上述语法格式修改上文代码

num1=20
num2=0
try:
	num3=num1/num2
except ZeroDivisionError:
	print("除数不可以为0.")

此时程序不会报错,当发现除数为 0 会进入异常处理,直接输出除数不能为 0。

try 表示测试代码部分是否存在异常,except 表示捕获异常,前提是出现异常。如果 try 语句中没有任何错误,except 中的代码不会执行。

还有一点需要注意,在 except 后面是异常对象,该异常对象我们设置为 ZeroDivisionError 这是因为已经知道是会出现这个异常,如果在编码过程中不知道会出现哪种异常,依旧会出现错误。

num1 = 20
num2 = "abc"
try:
    num3 = num1 / num2
except ZeroDivisionError:
    print("除数不可以为 0 ")

上述代码依旧会报错,报错的异常为:

Traceback (most recent call last):
  File "D:/gun/2/demo7.py", line 4, in <module>
    num3 = num1 / num2
TypeError: unsupported operand type(s) for /: 'int' and 'str'

如果想在 except 后面支持本异常,需要添加上 TypeError。

num1 = 20
num2 = "abc"
try:
    num3 = num1 / num2
except (ZeroDivisionError,TypeError):
    print("除数不可以为 0 ")

也可以分开编写:

num1 = 20
num2 = "abc"
try:
    num3 = num1 / num2
except ZeroDivisionError:
    print("除数不可以为 0 ")

except TypeError:
    print("除数类型不对")

该种写法在书写的时候需要预先知道会提示哪种异常,如果异常不清楚那可以省略异常对象,直接使用下述代码即可。

num1=20
num2="abc"
try:
	num3=num1/num2
except:
	print("除数不可以为0")

8.3 try… except…else 语句

在 try … except 语句后面可以增加一个 else 语句,该语句表示的含义可以按照如下描述进行理解,当出现异常的时候执行 except 语句中的代码,当无异常执行 else 语句代码。

num1=20
num2=1
try:
	num3=num1/num2
except ZeroDivisionError:
	print("除数不可以为0")
except TypeError:
	print("除数类型不对")
else:
	print("无异常,会被执行")

以上代码无错误,那 else 语句就会被执行到。

8.4 常见的异常类型

在编写代码的过程中,你需要掌握一些常见的异常类型,熟记它们可以帮助你快速进行错误排查。

  • AttributeError 某个对象没有属性
  • Exception 通用型异常对象
  • FileNotFoundError 找不到文件
  • IOError 输入输出异常
  • IndexError 索引异常
  • KeyError 键异常
  • NameError 对象名称异常
  • SyntaxError 语法错误
  • TypeError 类型错误
  • ValueError 值错误
    以上错误都属于常见错误,其中重点以Exception通用异常对象与SyntaxError语法错误为主,它们两个是最常出现的.
    很多时候其实直接使用通用异常对象Exception就可以了,不需要记住所有异常类型的.

8.5 捕捉多个异常

在上文已经接触过捕捉多个异常的语法格式了,可以在学习一下.

try:
	可能出错的代码块
except 异常对象1:
	异常处理代码块
except 异常对象2:
	异常处理代码块

8.6 一个except捕获多个异常

Python也支持使用一个except捕获多个异常,具体语法格式如下:

try:
	可能出错的代码块
except (异常对象1,异常对象2...):
	异常处理代码块

8.7 直接抛出异常

捕获到异常之后,可以直接抛出Python给内置好的异常信息,例如:

num1=20
num2=0
try:
	num3=num1/num2
except ZeroDivisionError as e:
	print(e)
except TypeError as e:
	print(e)
else:
	print("无异常,会被执行")

注意except后面异常对象使用as关键字起了一个别名叫做e,然后直接输出e就是Python内置好的错误信息了,这里的e可以为任意名称,遵循变量命名规则即可.

8.8 finally语句

try…except语句还可以和finally语句配合,形成下述语法格式:

try:
	可能出错的代码块
except:
	代码出错执行的代码块
else:
	代码正常执行的代码块
finally:
	无论代码是否有异常出现都会执行的代码块

finally语法需要与try语句配合使用,无论是否有异常出现都会执行该语句内容,具体代码大家可以自行测试即可.
关于异常部分,还有如下内容可以扩展。

  • 使用 raise 抛出异常
  • 使用 traceback 模块记录异常信息到文件中
  • 程序断言 assert

8.9 异常处理的使用

'a.json’文件不存在,下面代码会有异常,请编写异常控制代码,控制异常的最小范围,出现异常正常打印日志和堆栈

import json
import traceback
import logging
logger=logging.getLogger(__name__)

def load_json(file):
	with open(file,'r') as f:
		return json.loads(f.read())

def test():
	# TODO(You):
	ret=load_json('a.json')

if __name__=='__main__':
test()
# 请选出下列能正确实现这一功能的选项
# A.
try:
    ret = load_json('a.json')
    return {'err': 'success', 'result': ret}
except Exception as e:
    logger.error(f"load json exception:{str(e)}")
    logger.error(e.format_exc())
    return {'err': 'exception'}
# B.
try:
    ret = load_json('a.json')
    return {'err': 'success', 'result': ret}
except e:
    logger.error(f"load json exception:{str(e)}")
    logger.error(e.format_exc())
    return {'err': 'exception'}
# C.
try:
    ret = load_json('a.json')
    return {'err': 'success', 'result': ret}
except Exception(e):
    logger.error(f"load json exception:{str(e)}")
    logger.error(traceback.format_exc())
    return {'err': 'exception'}
# D.
try:
	ret=load_json('a.json')
	return {'err':'success','result':ret}
expect Exception as e:
	logger.error(f"load json exception:{str(e)}")
	logger.error(traceback.format_exc())
	return {'err':'exception'}
# D √
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值