Python是动态类型语言,使用变量时不需要做任何类型声明,这是Python相比其它语言的一个重要优势:它减少了我们的心智负担,让写代码变得更容易。尤其对于我们很多新手来说,“不用声明类型”无疑会让学Python这件事变得简单很多。
但任何事务都有其两面性。动态类型所带来的缺点是代码的可读性会因此大打折扣。
读读下面这段代码:
def remove_invalid(items):"""剔除items里面的无效的元素"""...
对于使用者来说,函数接收的items参数是什么类型?是一个装满数字的列表,还是一个装满字符串的集合?还是一个用户字典?对于调用者,根本无从得知。甚至对于编写者,过很长时间后,也可能会搞不懂了。
为了解决动态类型的可读性问题,最常见的办法是在函数文档(docstring)里做文章,把每个函数参数的类型与说明全部都写到函数文档里。
下面是增加了Python官方推荐的Sphinx格式文档后的代码:
def remove_invalid(items):"""剔除items里面的无效的元素""":param items:待剔除对象:type items:包含整数的列表,[int,...]...
上面代码中,在函数文档里,用:type items 注明了items是一个整数列表。调用人员读到就清楚了参数的类型。
标注类型的方法不止于这一种,在Python3.5版本以后,可以使用类型注解功能直接注明变量类型。只需要在变量后添加类型,并用冒号隔开即可,比如func(value: str),表示函数func的参数value是字符串类型。
使用类型注解后的上面代码如下:
from typing import Listdef remove_invalid(items: List[int]):"""剔除items里面的无效的元素"""...
List表示参数为列表类型,[int]表示里面的成员是整形。
typing是类型注解用到的主要模块,除了List以外,该模块内还有许多与类型有关的特殊对象,举例如下:
- Dict:字典类型,例如Dict[str,int]代表键为字符串,值为整形的字典。
- Callable:可调用对象,例如Callable[[str,str],List[str]]表示接收两个字符串作为参数,返回字符串列表的可调用对象。
- TextIO:使用文本协议的类文件类型,相应地,还有二进制类型BinaryIO.
- Any:代表任何类型
- 说明:“类型注解”只是一种有关类型的注释,不提供任何校验功能。要校验类型正确性,需要使用其他类型检查工具(如mypy等)。
不仅可以给变量加上类型注解,还可以给函数的返回值加上类型注解,如下代码做了演示:
1)下面代码没有任何类型注解:
class Duck:"""鸭子类:param color: 鸭子颜色"""def __init__(self,color):self.color = colordef quack(self):print(f"嗨,这是一只{self.color}的鸭子"}def create_random_ducks(number):"""创建一批随机颜色的鸭子:param number: 需要创建的鸭子数量"""ducks = []while number > 0:color = random.choice(['yellow','white','gray'])ducks.append(Duck(color=color))number -= 1return ducks
2)下面是添加了类型注解代码:
from typing import List
import random class Duck: def __init__(self, color: str): # 参数color类型为字符串 self.color = color def quack(self) -> None: # 函数返回值类型为None print(f"嗨,这是一只{self.color}的鸭子") def create_random_ducks(number: int) ->List[Duck]: # 参数number类型为整形 ducks: List[Duck] = [] # 变量ducks是一个列表,列表元素是Duck类型 while number > 0: color = random.choice(['yellow', 'white', 'gray']) # 这里对color变量进行类型注解 ducks.append(Duck(color=color)) number -= 1 return ducksducks = create_random_ducks(5)for duck in ducks:duck.quack()
- 从上面代码可以看出,通过-> 给函数返回值添加类型注解
- 可以用typing模块的特殊对象List来标注列表成员的具体类型,注意,这里用的是[],不是()
- 声明变量时候,可以为其加上类型注解,但类型注解是可选的,非常自由,比如上面代码中如下这行的color变量就没有注解。
color = random.choice(['yellow','white','gray'])
如果加上注解是这样子的:
color: str = random.choice(['yellow','white','gray'])
可以把Python里的类型注解当成一种用于提升代码可读性的特殊注释,因为它就像注释一样,只提升代码的说明性,不会对程序的执行过程产生任何实际影响,Python并不会做校验。
至于函数文档好,还是类型注解好,仁者见仁智者见智。我学习这块内容的理解是,函数文档还是要有的,给调用者(包括自己)更好地阅读,尤其使用Pycharm这类工具调用,会有很好的提示,这一点特别好。在编写函数时,对参数及返回值做注解也很有意义,不仅提升代码的可读性,可以让自己写函数体内的具体逻辑代码更清晰,或者做必要的验证,增强代码的健壮性。
本文主要摘自朱雷老师《Python工匠》书中内容,修改了代码部分内容。