• Python变量与注释高级用法


    Python变量与注释高级用法

    1.概述

    好的变量和注释并非为计算机而写,而是为每个阅读代码的人而写。变量与注释是表达作者思想的基础,他们对代码质量的贡献母庸质疑。

    2.变量

    2.1.变量解包

    1.什么是变量解包

    把一个可迭代对象的所有成员,一次性的赋值给多个变量的过程就是变量解包。

    2.变量解包语法

    # 变量解包
    username = ['zhangsan', '18']
    name, age = username
    print('name:{}, age:{} '.format(name, age))
    
    # 嵌套类型变量解包
    username = [1, ['zhangsan', 18]]
    number, (name, age) = username
    print('number:{}, name:{}, age:{}'.format(number, name, age))
    
    # 匹配模式解包
    data = ['zhangsan', 'banana', 'apple', 'orange', 18]
    name, *fruits, score = data
    print('name:{}, fruits:{}, score:{}'.format(name, fruits, score))
    
    # 切片解包
    data = ['zhangsan', 'banana', 'apple', 'orange', 18]
    name, fruits, score = data[0], data[1:-1], data[-1]
    print('name:{}, fruits:{}, score:{}'.format(name, fruits, score))
    
    # 变量解包用到for循环
    for name, age in [('zhangsan', 15), ('lisi', 18)]:
        print('name:{}, age:{}'.format(name, age))
    
    # 单下划线变量名
    username = ['zhangsan', 19]
    name, _ = username
    print(name, _)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2.2.给变量注明类型

    1.变量注明类型介绍

    python给变量注明类型,与java变量类型不同,python的变量类型只是一种提示功能,不提供任何校验功能。
    因此传入的变量类型与校验类型不一致也不会报错。

    变量注明类型语法非常简单,在变量名称后面用冒号分隔表名类型即可。

    2.变量注明类型示例

    # list表示参数为列表类型,int表示里面的成员是整形
    def remove_invalid(item: list[int]):
        print(item)
    
    
    # 传入符合变量类型参数
    remove_invalid([1, 2, 3])
    # 传入不符合变量类型参数,不影响函数执行结果。
    remove_invalid(1)
    
    # 类型注解使用demo
    class Duck:
        def __init__(self, color:str):
            self.color = color
        # 为quack方法注明返回值类型为None
        def quack(self) -> None:
            print(f"Hi, I'm a {self.color} duck")
    
    # -> List[Duck]:用typing模块的List对象为函数返回值标注具体类型
    def create_random_ducks(number:int) -> List[Duck]:
        # 为变量加上类型声明
        ducks: List[Duck] = []
    
        for _ in number:
            color = random.choice(['yellow', 'white', 'gray'])
            ducks.append(Duck(color=color))
        return ducks
    
    
    ducks = create_random_ducks((1,2,3))
    for duck in ducks:
        duck.quack()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2.3.变量命名原则

    给变量起名主要有两种流派:一是通过大小写界定单词的驼峰命名,例如Java语言。二是通过下划线连接的蛇形命名,例如python语言。

    • 遵循PEP8原则
    • 描述性要强
    • 长度尽量短
    • 变量注明类型
    • 超短命名

    1.遵循PEP8原则

    PEP8原名《Python Enhacement Proposal #8》译为《8 号 Python 增强规范》为代码编写风格提供了指南,变量命名部分规范如下。

    • 普通变量,使用蛇形命名法,比如max_value
    • 常量,采用全部大写字母,使用下划线连接,比如 MAX_VALUE
    • 仅内部使用变量,在变量前增加下划线前缀,比如 _local_var
    • 变量名称与python关键字冲突时,在变量末尾追加下划线,比如 class_

    2.描述性要强

    写作过程中一项重要的工作就是为句子斟酌恰当的词语,不同的词语描述性的强弱是不同的。比如”冬天傲骨的梅花“ 就比 ”花“ 描述性要强。为变量命名和词语一样,同样有描述性强弱之分。
    下面是描述性强弱不同的变量,对比可以感受到描述性强的变量名称使代码更易读。

    # 描述性弱的变量名称:看不出它在描述什么
    vlaue = process(s.strip())
    
    # 描述性强的变量名称:从用户输入参数中解析出用户名称,并剔除参数中的空格。
    username = extract_username(input_string.strip())
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.长度尽量短

    假如一个特别长的重复出现,读者不会觉得它精确,反而是啰嗦难读。在保证描述性清晰前提下,尽量让名字简短易读,通常控制在4个单词内。

    4.变量注明类型

    虽然python的变量不需要声明类型,但是为了提升可读性,我们可以为变量注明类型。
    除了为变量注明类型外,还有约定俗称的变量名称与类型建立匹配关系,下面是一些变量名称和类型匹配的例子。

    • 匹配布尔值类型的变量名
    变量名含义说明
    is_superuser是否是超级用户is 表示是或不是
    has_errors有没有错hans 表示有或没有
    allow_empty是否允许空值allow表示是否允许

    5.超短命令

    在变量命名中有一类名称比较特别,只有一两个字母,通常他们分为两类,一类是大家约定俗称的短名字,另一类是起别名。

    约定俗称常用名称

    • 数组索引三剑客 i、j、k
    • 某个整数 n
    • 某个字符串 s
    • 某个异常 e
    • 文件对象 fp

    长名称起别名

    is_not_normal as l
    
    • 1

    3.注释

    注释不会影响代码的行为,它会影响代码的可读性。

    3.1.注释类型

    python的注释分为两种,一种是代码内注释,一种是函数、类的注释也称为接口注释。

    行内注释

    # 使用strip()去掉空格的好处:
    # 1.数据库保存数据时占用空间更小
    # 2.不必因为用户多打了空格而要求用户重新输入。
    
    username = extract_username(input_string.strip())
    
    • 1
    • 2
    • 3
    • 4
    • 5

    接口注释

    class Person:
    	# 使用三个单引号或三个双引号就是接口注释。
    	'''人
    	:param name: 姓名
    	: param age: 年龄
    	: param favrite_color: 最喜欢的颜色
    	'''
    	def __init__(self, name, age, favrite_color):
    		self.name = name
    		self.age = age
    		self.favrite_color = color
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.2.错误使用注释案例

    1.用注释屏蔽代码

    在编程中会用注释屏蔽代码,如果这些代码不需要了可以直接删掉,如果需要用到这些代码可以从Git仓库中找到。临时注释掉的大段代码,对于阅读代码的人来说是一种干扰,没有任何意义。

    2.用注释复述代码

    # 调用strip()去掉空格
    input_string = input_string.strip()
    
    • 1
    • 2

    上面这样的注释完全是冗余的,因为读者从代码本身就能读到注释里的信息。好的注释应该是这样

    # 如果将带有空格的参数传递到后端处理,可能会造成服务奔溃
    # 因此使用strip()去掉收尾空格
    input_string = input_string.strip()
    
    • 1
    • 2
    • 3

    注释作为代码之外的说明性文字,应该尽量提供那些读者无法从代码里读出的信息,描述代码为什么要这么做,而不是简单复述代码本身。

    除了为什么的解释性注释外,还有一种注释也很常见:指引性注释
    这种注释不复述代码,而是简明扼要概括代码功能,起到”代码导读“作用。
    指引性注释并不提供代码里读不到东西——假如没有注释,耐心读完所有代码也能知道代码做了什么。指引性注释就是降低代码认知的成本,让我们更容易理解代码的意图。

    指引性注释示例

    # 初始化访问服务的client对象
    token = token_service.get_token()
    service_client = ServiceClient(token = token)
    service_client.ready()
    
    • 1
    • 2
    • 3
    • 4

    3.用接口注释阐述函数实现细节

    在编写接口注释时,经常会看到下面的情况。

    def resize_image(image, size):
    	'''将图片缩放到指定尺寸,并返回新的图片。
    	该函数将使用pilot模块读取文件对象,然后调用.resize()方法将其缩放到指定尺寸。
    	但由于pilot模块自身限制,这个函数不能很好的处理过大文件,当文件超过5MB时,resize()方法的性能
    	就会急剧下降,因此超过5MB文件,使用resize_big_image()替代,后者基于Pillow模块开发,
    	很好的解决了内存分配问题,确保更好的性能。
    
    	:param image: 图片文件对象
    	:param size: 包含宽高的元组(width, height)
    	:return: 新图片对象
    	'''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这段接口注释最主要的问题在于过多的阐述了函数实现的细节,提供了太多其他人并不关系的内容。

    接口注释主要是给函数或类的使用者看的,它存在的最主要价值,是让人们不用逐行阅读函数代码,就能从注释中知道该如何使用这个函数,以及使用时需要注意事项

    在编写接口注释时我们应该站在函数设计者的角度,着重描述函数的功能,参数等。而函数自身实现细节无需放在接口注释中,放到函数内部代码注释即可。

    下面是改进后的接口注释

    def resize_image(image, size):
    	'''将图片缩放到指定尺寸,并返回新的图片。
    	注意:当文件超过5MB时,请使用resize_big_image()
    
    	:param image: 图片文件对象
    	:param size: 包含宽高的元组(width, height)
    	:return: 新图片对象
    	'''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.编程建议

    4.1.变量使用建议

    1.保持变量一致性

    在使用变量时,需要保证他在两个方面的一致性:名字一致性与类型一致性。

    • 名字一致性是指在同一个项目、模块、函数中,对同一类事物称呼不要变来变去。比如用户头像叫做user_avatar_url,那么在其他地方不要把它改成user_profile_url。否则读代码的人不知道这两个变量名称指的是否是同一个东西。
    • 类型一致性是指不要把一个变量重复指向不同类型的值。举个例子:
    def():
    	#user 是一个Dict类型
    	user = {'data':['zhangsan','wangwu']}
    	# user 这个名字好用,重复使用它,把它变成List
    	user = []
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.变量定义尽量靠近使用

    定义变量应该把它们放到每段 “各司其职” 的代码头部,缩短变量从初始化到使用的 “距离”。当读者阅读代码时,可以更容易理解代码逻辑,而不是来回翻阅代码查看变量是在什么时候定义的,在什么时候使用的。

    3.定义临时变量提升可读性

    当代码中遇到复杂的逻辑时,判断条件就会变得复杂,这时候可以采用临时变量简化判断条件的复杂度,提升代码的可阅读性。

    举例:定义临时变量提升代码阅读性

    # 为所有女性或者级别大于3的活跃用户发放1000个金币
    if user.is_active and (user.sex == 'female' or user.level > 3):
    	user.add_coins(1000)
    
    # 上面业务逻辑使判断条件变得复杂,阅读起来有些费劲,这时候我们可以把后面复杂的表达式赋值给一个临时变量,代码阅读性就会有所提升,下面是例子。
    
    user_is_eligible = user.is_active and (user.sex == 'female' or user.level > 3)
    if user_is_eligible:
    	user.add_coins(1000)
    
    '''
    在新的代码中,“计算用户合规的表达式” 和 “判断合规发送金币的条件分支” 这两段代码不再揉捏在一起,
    而是添加了一个可读性强的变量作为缓冲,不论是代码的可读性还是维护性都因为这个变量增强了。
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.同一作用域内不要有太多的变量

    函数越长,用到的变量就越多。但是人脑记忆是有限的,太多的变量会使代码变得难读。如果函数内变量太多,通常是函数承担了太多的职责,把复杂的函数拆分为多个小涵数,代码的整体复杂度会降低。

    5.能不定义变量就别定义

    在编写代码时,我们会下意识的定义很多变量,好为未来调整代码做准备,但是你所想的未来也许永远不会来。
    下面是一个定义临时变量过多的例子,我们对它做了优化。

    # 定义过多的临时变量会让阅读代码的读者觉得啰嗦,阅读性不好。
    def get_best_trip_by_user_id(user_id):
    	# 下面的值可能会修改,二次使用,先把它定义成变量吧
    	user = get_user(user_id)
    	trip = get_best_trip(user_id)
    	result = {
    		'user': user,
    		'trip': trip
    	}
    	return result
    
    # 对上面的代码进行优化,去掉多余的临时变量。
    '''
    这样的代码就像删掉啰嗦的句子,变得更精炼,更易读。
    '''
    def get_best_trip_by_user_id(user_id):
    	return {
    		'user': get_user(user_id),
    		'trip': get_best_trip(user_id) 
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4.2.注释使用建议

    1.空行也是一种"注释"

    在写代码的时候,我们可以适当地在代码中插入空行,把代码按不同逻辑块分隔开,这样做能有效提升代码的可读性。

    2.先写注释,后写代码

    在写代码时有一个好习惯值得推荐:先写注释,后写代码。

    比如在开发代码过程中写的最多的就是函数,封装业务逻辑也是函数,下面就来聊聊函数开发的好习惯。
    每个函数的名称与接口注释,其实是一种比函数内部更为抽象的东西。你需要在函数名和短短几行注释里,把函数内代码所做的事情,高度浓缩的表达清楚。

    正因为如此,接口注释其实可以当成一种协助你设计函数的前置工具。这个工具用法很简单:假如你没法通过几行注释把函数的职责描述清楚,那么整个函数的合理性就该打个问号

    举例:
    你在写一个函数process_user(),编写函数注释时,你发现在写了好几行文字后,仍然没法把函数的职责描述清楚,因为它可以同时完成好多件不同的事情。这时你就该意识到,process_user()函数承担了太多的职责,解决办法就是直接删掉它,设计更多单一职责的子函数来替代。

    先写注释的另一个好处是:不会漏掉任何应该写的注释。

    为什么大家会漏掉注释?我的一个猜测是:程序员在编写函数时,总是跳过接口注释直接开始写代码。而当写完代码,
    实现函数的所有功能后,他就对这个函数失去了兴趣。这是他最不愿意做的事,就是回过头去补写函数的注释,
    级别写了也只是草草对付了事。

    如果遵守 “先写注释,后写代码” 的习惯,我们就可以完全避免上面的问题。养成这个好习惯 ,其实很简单:在写出一句有说服力的接口注释前,先别写任何函数代码。

  • 相关阅读:
    98%的人都不会使用这6种地图可视化方法,学会直接涨薪5K
    Java并发编程面经2
    FPGA project : sdram
    【毕业设计】深度学习车道线检测与识别系统 - python 机器视觉
    layui移除(删除)table表格的一行
    测开(自动化测试selenium(WebDriver API))
    进程管理--CFS调度器(1)
    利用pytorch自定义CNN网络(三):构建CNN模型
    Python实现PPT演示文稿中视频的添加、替换及提取
    Maxwell 一款简单易上手的实时抓取Mysql数据的软件
  • 原文地址:https://blog.csdn.net/m0_38039437/article/details/126182699