• 这些包括我在内都有的Python编程陋习,趁早改掉


    在这里插入图片描述
    B站|公众号:啥都会一点的研究生

    相关阅读

    整理了几个100%会踩的Python细节坑,提前防止脑血栓
    整理了十个100%提高效率的Python编程技巧,更上一层楼
    Python-列表,从基础到进阶用法大总结,进来查漏补缺
    Python-元组,从基础到进阶用法大总结及与列表核心区别,进来查漏补缺
    Python-字典,从基础到进阶用法大总结,进来查漏补缺
    Python-集合,从基础到进阶大总结,进来查漏补缺
    订阅专栏 ===> Python

    首先第一个例子,很多同学都有这个习惯,包括我自己很长一段时间都用这种方式,难看且繁琐

    def case_1(name, score):
        if score > 60.0:
            print("Congratulations " + name + "! your score is " + str(score))
        else:
            print("Sorry " + name + ", you didn't pass the exam")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    但其实,使用f-string能简化编写方式,提升效率

    def case_1(name, score):
        if score > 60.0:
            print(f"Congratulations {name}! your score is {score}")
        else:
            print(f"Sorry {name}, you didn't pass the exam")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    第二个,有的同学,可能知道Python中None,False,0,空列表,空元组,空集合,空字典,空钱包等都表否定,如这个例子,虽然没错,但在工程上代码长、变量多的时候可读性将变差

    def case_2(lst):
        my_list = []
        if lst:
            my_list = lst[:]
        else:
            my_list.append(1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    最好规范编写

    def case_2(lst):
        my_list = []
        if len(my_list) > 0:
            my_list = lst[:]
        else:
            my_list.append(1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    说到这个,在Python中使用if结合bool(x)len(x)或其他内置函数,等效于if x,但还是得综合考虑可读性

    def case_3(x):
        if x:
            pass
        
        if bool(x):
            pass
        
        if len(x):
            pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个例子很简单,但初学者确实容易混淆的用法,想实现x的y次幂,下意识地就会写成这样

    def case_4(x, y):
        return x ^ y
    
    • 1
    • 2

    但其实这是按位异或,正确的应该这样

    def case_4(x, y):
        return x ** y
    
    • 1
    • 2

    下一个,当需要对文件进行读写时,很多人习惯写成这样

    def case_5(filepath):
        f = open(filepath, "w")
        f.write("Hello world\n") # here
        f.close()
    
    • 1
    • 2
    • 3
    • 4

    但不知道的是,当写入发生错误时,该文件永远不会被关闭,正确的做法是使用with,即使发生了异常也能正确关闭

    def case_5(filepath):
        with open(filepath) as f:
            f.write("Hello world\n")
    
    • 1
    • 2
    • 3

    下一个,当程序中涉及数值很大的变量,通常你可能写成如下形式

    def case_6():
        x = 10000000
    
    • 1
    • 2

    但其实会影响阅读,而若使用这种方式会变得简洁明了

    def case_6():
        x = 10_000_000
    
    • 1
    • 2

    下一个,很多人喜欢用print来debug程序

    def case_7():
        print("debug info")
        print("normal info")
        print("error info")
    
    • 1
    • 2
    • 3
    • 4

    其实使用logging打印日志更加清晰,可以很明显的看到程序输出,且还能保存在本地查阅,虽然我自己很多时候也是print,确实方便

    import logging
    
    
    def case_8():
        logging.debug("debug info")
        logging.info("normal info")
        logging.error("error info")
        
    def main():
        level = logging.DEBUG
        fmt = "[%(level)s] %(asctime)s - %(message)s"
        logging.basicConfig(level=level, format=fmt)
        case_8()
    
    >>> [DEBUG] 2022-10-23 14:54:55,763 - debug info
    [INFO] 2022-10-23 14:54:55,763 - normal info
    [ERROR] 2022-10-23 14:54:55,763 - error info
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    下一个,当定义函数时,若存在可变类型参数,尤其需要小心

    def case_9(n, lst=[]):
        lst.append(n)
        return lst
    
    lst1 = case_9(0) # [0]
    lst2 = case_9(1) # [0, 1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    因为参数的默认值是在定义函数时定义的,而不是运行时,在该例中,每一次的调用都共享同一个列表,所以除开第一次外,之后每次调用都是从前面的结果开始添加数据,可以稍作改变达到目的

    def case_9(n, lst=None):
        if lst is None:
            lst = []
        lst.append(n)
        return lst
    
    lst1 = case_9(0) # [0]
    lst2 = case_9(1) # [1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    说到这个可变类型,球球一定注意当你把列表、字典这种传给函数时稍不注意就会改动原始数据

    def case_10(lst):
        lst2 = lst
        lst2.append(1)
    
    init_list = [0, 1, 2]
    
    case_10(init_list) # init_list : [0, 1, 2, 1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时需要对其进行拷贝,构造新的对象

    def case_10(lst):
        lst2 = lst[:] # copy() deepcopy()
        lst2.append(1)
    
    init_list = [0, 1, 2]
    
    case_10(init_list) # init_list : [0, 1, 2]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    遍历字典时,默认是遍历键,这两种方式其实是相同的

    def case_11():
        d = {"a": 1, "b": 2, "c": 3}
        for key in d:
            pass
        
        for key in d.keys():
            pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    关于推导式,不仅适用于列表,而元组、字典、集合均可以使用其各自的推导式

    def case_12():
        data = [0, 1, 2, 3]
        d = {i: i * i for i in data}
        l = [i * i for i in data]
        s = {i * i for i in data}
        t = (i * i for i in data)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    下一个,我们可以借助元组来进行解包,在Python中,其实形如x这种类型的数据都是元组,只是没穿上括号的衣服,类似的还有return返回值

    def case_13():
        x = 1, 2 # tuple
        d1 = x[0]
        d2 = x[1]
    
    • 1
    • 2
    • 3
    • 4

    下一个,很多时候我们会借助time库统计程序运行时间,并习惯使用两个time.time()相减的方式计算

    import time
    
    def case_14():
        t1 = time.time()
        time.sleep(1)
        t2 = time.time()
        print(t2 - t1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    time.perf_counter()具有最高测量分辨率的时钟,统计结果更加准确,此外,time.clock已经在3.8中被废除了

    import time
    
    def case_14():
        t1 = time.perf_counter()
        time.sleep(1)
        t2 = time.perf_counter()
        print(t2 - t1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    下一个,使用isinstance代替==检查类型,避免如namedtuple这种子类带来的判断错误问题

    from collections import namedtuple
    
    def case_15():
        line = namedtuple('line', ['k', 'b'])
        l = line(1, 5)
        
        if type(l) == tuple:
            print("it's a tuple") 
        else:
            print("it's not a tuple") # √
        
        if isinstance(l, tuple):
            print("it's a tuple") # √
        else:
            print("it's not a tuple")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    以上就是本期的全部内容,整理不易,如果有帮助到你就点赞关注吧,我是啥都生,我们下期再见~

  • 相关阅读:
    【Redis】# 常见报错Unsatisfied dependency、设置密码、主从配置
    【面试八股总结】MySQL索引(二):B+树数据结构、索引使用场景、索引优化、索引失效
    机器学习常识:初学者应该知道的10 大机器学习算法
    基于语义感知SBST的API场景测试智能生成
    ABP - 缓存模块(2)
    【JVM】JVM相关机制
    亚信科技亮相南京软博会,数智赋能百行千业
    Java项目:房屋租赁管理系统(java+SpringBoot+Vue+Maven+Mysql)
    大赛报名 | 免费体验V853芯片!“华秋电子X全志在线开源硬件设计大赛”开始报名啦
    PostgreSQL的学习心得和知识总结(八十六)|深入理解PostgreSQL数据库HOOK技术及开源hooks文档介绍
  • 原文地址:https://blog.csdn.net/zzh516451964zzh/article/details/127473697