欢迎光临散文网 会员登陆 & 注册

[python] 使用typing标注在外部脚本编辑器中获得自动补全

2022-09-18 00:39 作者:小小の我  | 我要投稿

houdini发布py3版本已经一年多了,新版已经移除了对py2的兼容支持,我想起来上次发了篇配置vscode连接houdini的专栏

上期指路:vscode连接houdini配置python开发环境

回头看看这py3不是来了吗,就分享一下如何在vscode中利用typing标注来获取自动补全吧

好久没写东西的我完全不知道怎么连接vscode,还是照着之前自己的教程一步步做才成功配置好,原来写教程给人看也就图一乐,真教程还是得当备忘录

使用typing模块可以让python这种动态语言能像静态语言一样拥有固定的变量类型,但是大部分时候它不影响代码的运行,只是对人类起到提示作用,对编辑器起到辅助解析作用

首先来看看没有typing的时候变量与函数在vscode中的解析

在vscode中,如果函数的返回类型是在函数内部就定义好的,那么我们调用函数的时候vscode可以帮助我们解析返回值的变量类型,鼠标放在函数上就能显示出来

上图中的函数内部使用了isinstance函数来分辨var1参数是否是一个字符串,如果是,foo函数返回的类型就是字符串,不是的话会返回None(python函数中没有return时返回None),所以在下面我调用了foo函数时,vscode自动解析出了foo的参数与返回值的类型

(var1: Any)中的Any的意思就是foo中var1参数的类型是任何类型都可以的,因为我们没有指定var1必须是一个str

而后面有一个 -> (str | None), 代表的是该函数的返回类型,可能是str或None

这只是一个例子,如果函数的参数和返回值都不确定的话就都是Any了

对于内部没有显式类型操作的函数,就无法判断具体会返回什么类型了

检查node参数是否是subnet,如果是就在内部创建一个null

上面这个函数在houdini中检查node参数是否是子网络节点类型,如果是就在其内部创建一个null节点,否则输出错误日志

对于这种很普遍的函数,vscode并不知道node的变量类型,在函数内部操作的时候实例方法都是白色的,代表vscode并不知道这些方法是否存在,而且把返回值赋予给变量,也只能得到一个Any这样毫无提示作用的结果

虽然运行起来没问题,但是码字的时候完全没有自动补全,所有方法和属性都需要手动输入完整不能出错,无异于txt中盲打代码,但我们很清楚这段代码的运行环境,也清楚node参数是一个节点类型,返回值是hou.Node或None

一个常用的方法是在函数顶层使用保护条款来确定参数类型,比如条件语句、assert等操作

一个分离路径字符串最后一级的函数,split方法是黄色代表能正确解析

对比foo4中的split方法,前两种函数里都正确解析出了var的字符串类型

但不停的使用保护条款来确定函数类型在一套嵌套比较紧密的处理逻辑中既显得冗余又一定程度加重了运行负担,而且如果传入多个不同类型的参数的话一个个检查类型简直像是跑了八百里找个厕所就为放个P


而typing标注正是用来解决这种问题的好帮手

我先简单说明一下常用方法,深入了解请参考下面typing的官方文档说明:

https://docs.python.org/zh-cn/3/library/typing.html


typing引入了新的写法可以在定义变量和函数的时候让用户标注类型,方便编辑器对用户自定义的变量和函数做解析

先来定义一个简单的加法,比如我想输出一个文件夹的名字加上某天的日期作为后缀,合起来成为txt文件名字

显示为白色的方法都只能手动输入,因为没有自动补全

如果我们确定path_是一个str类型,date_是一个date类型,那就可以在定义形参的时候使用冒号为形参指定类型

这样调用方法的时候编辑器就预先知道了参数类型,也就能帮我们补全了

而对于houdini的hou package中没有返回值的函数,可以用 -> 标志来标注函数的返回值类型,比如上面演示的create_dot函数

为我们的自定义函数标注输出类型为hou.Node,之后调用函数获得的变量类型也能被vscode解析到了

但官方文档说了这个标注并不会影响代码的运行,也就是说你如果传入了和标注不匹配的参数其实并不影响函数运行,即使报错也只是代码的逻辑问题导致的,和typing无关

比如一个简单的sum函数

使用int标注变量类型而传入字符串参数

由于两个字符串和两个数字一样可以进行相加运算, 这个函数实际不会报错,但vscode会以我们标注的类型为优先参考,假装没看见我们传进去两个字符串的事情

那么如果我们希望这个函数既能运算int又能算float和str就要使用合并类型来标注了

要从typing模块中导入Union为参数标注多个可能的类型,Union[多个类型,逗号分开]

指定了多个类型之后,补全列表也会把所有可能的方法属性都列出来

但这个函数实际上是有可能报错的,两个数字或两个字符串都可以相加,但一个数字和一个字符串就不能相加了,或许应该用可变参数定义统一的形参然后附加保护条款防止字符串参与数字银趴

好像复杂了不少,所以最终我还是仅仅放了个P是吗

并不是,只是我举的例子像个P(而且sum是内置函数),这个sum就到此为止了,还是要继续解决hou package的问题,谈下一话题

如果只是简单创建一个变量,并不想把它塞到函数里的话,可以直接在定义的变量处加标注

这是一个方便的方式,可以直接指定变量类型,但相信做为一个只是偶尔写个脚本的菜鸡cg“艺术家”的你..和我

一样,虽然想法天花乱坠,但实际操作往往都是for循环

selectedNodes和maya中的ls一样都是返回的一个节点列表,不能对一个列表标注节点类型,又不想在for循环里再加个条件来判断类型

与Union一样,typing也可以标注一个容器类型并且为它指定列表内对象的类型

在tuple内指定对象类型,for循环自动解析迭代对象的类型

而且容器类型支持嵌套

返回   选择的 多个subnet节点  的  子节点  的  两层嵌套列表,仍然可以正常解析

有一个没用的知识,对于我们这种经常for循环的人来说,tuple和list大多数时候都一样用,只是不同生成逻辑会返回不同的类型

typing中有一个Sequence类型是tuple, list, set这些列表类型的父类,标注形参类型时为这些有相似属性的容器类型统一使用Sequence,标注返回值时再根据自己函数的具体输出类型标注list或tuple等

返回节点列表中节点的输入节点的列表

大部分时候要考虑API给的函数中没有输出的情况,所以返回值的List中除了有节点类型还有None类型

处理链式调用不能补全的情况

对于oop来说链式调用是不可缺少的,但由于hou的解析问题,为了获得补全难免会破坏这种流畅的调用方式,我在这里总结了几种对于node.parm.eval这种常用获取属性值的方式的写法

我用的是vscode的python默认主题色,你可以把主题调成更艳一点的颜色来增加获得补全的成就感

更多类型和自定义类可以参考官方文档深入了解,我一个臭写循环的也就用这些基本功能就够了

尽管py2已经停更几年了,但是各个软件因为工程量过于庞大还是最近一两年才陆陆续续加入了对py3的支持

因为本人小圈子内都是CG从业者,并不是程序员出身,学习python也都是从软件本身出发的,我发现很多朋友对于py3基本是毫无性趣,因为软件不支持

py3相比py2有高得多的便利性,求求某些公司的流程内快点更新软件版本吧


[python] 使用typing标注在外部脚本编辑器中获得自动补全的评论 (共 条)

分享到微博请遵守国家法律