python测网络连通性_Python基础5之编程风格

965097cf55ad022b323cffe2732b529b.png

我的完整施工计划

目前已完成以下四期Python专题:

1我的施工计划

2数字专题

3字符串专题

4列表专题

5流程控制专题

今天讨论 Python 编程风格,如何写出更加Pythonic的代码是本篇讨论的话题。

基本目录结构:

  • 1 基本编程习惯

    • 1.1 多余的空格

    • 1.2 是否为 None 判断

    • 1.3 lamda 表达式

    • 1.4 最小化受保护代码

    • 1.5 保持逻辑完整性

    • 1.6 使用语义更加明确的方法

  • 2 EAFP 防御编程风格

  • 3 LBYL 防御编程风格

    • 3.1 程序每次运行都要检查

    • 3.2 很难一次考虑所有可能异常

    • 3.3 代码的可读性下降

1 基本编程习惯

1.1 多余的空格

以下函数赋值符合习惯:

foo(a, b=0, {'a':1,'b':2}, (10,))

但是,下面出现的多余空格都不符合习惯:

# 这些空格都是多余的
foo ( a, b = 0, { 'a':1, 'b':2 }, (10, )) 

下面代码,有空格又更符合习惯:

i += 1
num = num**2 + 1
def foo(nums: List)

尤其容易忽略的一个空格,增加函数元信息时要有一个空格:

def foo(nums: list): # 此处根据官方建议nums: list间要留有一个空格
    pass

1.2 是否为 None 判断

判断某个对象是否为None,下面符合习惯:

if arr is None:
    pass

if arr is not None:
    pass

下面写法不符合习惯,一般很少见:

if arr == None:
    pass

特别的,对于list,tuple,set,dict,str等对象,使用下面方法判断是否为None更加符合习惯:

if not arr: #为 None 时,满足条件
    pass
    
if arr: # 不为 None 时,满足条件
    pass

1.3 lamda 表达式

lambda 表达式适合一些key参数赋值等,一般不习惯这么写:

f = lambda i: i&1

下面写法更加符合习惯:

def is_odd(i): return i&1

1.4 最小化受保护代码

要想代码更健壮,我们一般都做防御性的工作,最小化受保护的代码更加符合习惯,如下为了防御键不存在问题,加一个try:

try:
    val = d['c']
except KeyError:
    print('c' not existence)

上面写法是合理的,但是下面代码在捕获KeyError时,又嵌套一个函数是不符合习惯的:

try:
    val = foo(d['c']) # 这样写也会捕获foo函数中的KeyError异常
except KeyError:
    print('c' not existence)

这样写也会捕获foo函数中的KeyError异常,不符合习惯。

1.5 保持逻辑完整性

根据官方指南,只有if逻辑return,而忽视可能的x为负时的else逻辑,不可取:

def foo(x):
    if x >= 0:
        return math.sqrt(x)

建议写法:

def foo(x):
    if x >= 0:
        return math.sqrt(x)
    else:
        return None

或者这样写:

def foo(x):
    if x 0:
        return None
    return math.sqrt(x)

所以,不要为了刻意追求代码行数最少,而忽视使用习惯。

1.6 使用语义更加明确的方法

判断字符串是否以ize结尾时,不建议这样写:

if s[-3:] == 'ize':
    print('ends ize')

使用字符串的endswith方法判断是否以什么字符串结尾,显然可读性更好:

if s.endswith('ize'):
    print('ends ize')

以上这些只要平时多加注意,理解起来不是问题。其实除了PEP8指定的这些代码编写习惯外,还有一种与代码健壮性息息相关的编程风格,今天重点介绍这方面的编程习惯。

2 EAFP 防御编程风格

为了提升代码的健壮性,我们要做防御性编程,Python中的tryexcept就是主要用来做这个:

d = {'a': 1, 'b': [1, 2, 3]}

try:
    val = d['c']
except KeyError:
    print('key not existence')

try块中代码是受保护的,如果键不存在,except捕获到KeyError异常,并处理这个异常信息。

而下面的代码,一旦从字典中获取不存在的键,如果没有任何try保护,则程序直接中断在这里,表现出来的现象就是app直接挂掉或闪退,这显然非常不友好。

d = {'a': 1, 'b': [1, 2, 3]}
val = d['c']

再举一个tryexcept使用的例子,如果目录已存在则触发OSError异常,并通过except捕获到然后在块里面做一些异常处理逻辑。

import os
try:
    os.makedirs(path)
except OSError as exception:
    if exception.errno != errno.EEXIST: 
        raise # PermissionError 等异常
    else:
        # path 目录已存在

以上这种使用tryexcept的防御性编程风格,在Python中有一个比较抽象的名字:EAFP

它的全称为:

Easier to Ask for Forgiveness than Permission.

没必要纠结上面这句话的哲学含义。

知道在编程方面的指代意义就行:首先相信程序会正确执行,然后如果出错了我们再处理错误

使用tryexcept这种防御风格,优点明显,try里只写我们的业务逻辑,except里写异常处理逻辑,几乎无多余代码,Python指南里也提倡使用这种风格。

但是任何事物都有两面性,这种写法也不例外。那么,EAFP防御风格有何问题呢?它主要会带来一些我们不想出现的副作用。

举一个例子,如下try块里的逻辑:出现某种情况修改磁盘的csv文件里的某个值,这些逻辑都顺利完成,但是走到下面这句代码时程序出现异常,进而被except捕获,然后做一些异常处理:

try:
    if condition:
        revise_csv()  # 已经污染csv文件

    do_something()  # 触发异常
except Exception:
    handle_exception()

由于try块里的逻辑分为两步执行,它们不是一个原子操作,所以首先修改了csv文件,但是do_something却出现异常,导致污染csv文件。

其实,除了以上EAFP防御性编程风格外,还有一种编程风格与它截然不同,它虽然能很好的解决EAFP的副作用,但是缺点更加明显,所以Python中不太提倡大量的使用此种风格。

3 LBYL 防御编程风格

再介绍另一种编程风格:LBYL

它的特点:指在执行正常的业务逻辑前做好各种可能出错检查,需要写一个又一个的ifelse逻辑。

EAFP风格的代码:

d = {'a': 1, 'b': [1, 2, 3]}

try:
    val = d['c']
except KeyError:
    print('key not existence')

使用LBYL来写就是如下这样:

if 'c' in d:
    val = d['c']
else:
    print('key not existence')

EAFP风格的代码如下:

import os
try:
    os.makedirs(path)
except OSError as exception:
    if exception.errno != errno.EEXIST: 
        raise # PermissionError 等异常
    else:
        # path 目录已存在

使用LBYL来写就是如下这样:

import os

if not os.path.isdir(path):
    print('不是一个合法路径')

else:
    if not os.path.exists(path):
        os.makedirs(path)
    else:
        print('路径已存在')

通过以上两个例子,大家可以看出LBYL风格和EAFP风格迥异。

LBYL的代码if和else较多,这种风格会有以下缺点。

3.1 程序每次运行都要检查

程序每次运行都要检查,不管程序是不是真的会触发这些异常。

if 'c' in d: # 每次必做检查
    val = d['c']
    
if not os.path.isdir(path): # 每次必做检查
    print('不是一个合法路径')

else:
    if not os.path.exists(path): # 每次必做检查
        os.makedirs(path)
    else:
        print('路径已存在')

3.2 很难一次考虑所有可能异常

很难一次性考虑到所有可能的异常,更让人头疼的事情是,一旦遗漏某些异常情况,错误经常不在出现的地方,而在很外层的一个调用处。这就会导致我们花很多时间调试才能找到最终出错的地方。

def f1()if con1:
        # do1()
   if con2:
        # do2()
   # 但是遗漏了情况3,未在f1函数中报异常

3.3 代码的可读性下降

要写很多与主逻辑无关的if-else ,程序真正的逻辑就变得难以阅读。最后导致我们很难看出这个只是判断,还是程序逻辑/业务的判断。但是,如果用try-catch,那么try代码块里面可以只写程序的逻辑,在except里面处理所有的异常。

结论:就Python语言,推荐使用EAFP风格,个别受保护的块,若无法实现原子操作的地方可以使用LBYL风格。

《end》

你可能会喜欢

  • Jmeter关联系列_数据驱动中的业务逻辑关联

  • docker搭建接口自动化持续集成框架

  • python28:迷宫游戏最短路径算法

  • 4300 字Python列表使用总结,用心!

  • 盘一盘 Python 系列基础篇十一之 机器学习 Sklearn

  • 盘一盘 Python 系列特别篇十八之 日期时间 DateTime

  • Linux环境部署之ubuntu网络配置

  • 性能测试指标7:性能测试的阶段性工作

  • jmeter之对jar包进行调用

  • jmeter之爬取网络图片

  • 软件质量保障体系图

  • 研发过程中的测试工作

  • APP测试流程及测试点

  • WEB测试范围小结

作为一个对测试有情怀的人,希望本公众号的文章能够帮助到大家,测试这条路不容易,请大家多多帮忙推广,将越来越多志同道合的小伙伴聚集,在这条道路上互相扶持,一起走下去……

cf4fd4e4ab599d2232819708c104dd5d.png

测试交流,加我备注【测试交流】拉入交流群,更有不定期资料赠送,敬请期待

36067578c702c4a051a6d88b26a52ebb.png

福利来一波~~~

关注公众号回复以下信息送免费资料
回复Jenkins 领取Jenkins学习资料回复Jmeter 领取Jmeter学习资料

回复Java   领取Java学习资料

回复Python 领取python入门资料

回复RobotFramework   领取RobotFramework 框架搭建资料

本文转载自【公众号:Python与算法社区

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值