可能是因为我是从 Java 转 Python 的,我把 Python 当作是我的第二语言。
总所周知,Java 是强类型的语言,传参的时候类型错误编译是不会通过的。
为了让 Python 能像 Java 那样,我的想法是在方法开始的地方自己手动做类型判断。
类似这种:
def getHTML(url): if type(url) != str: raise TypeError("url 参数只能是字符串"")
这么做的目的是为了防止传入的参数类型不正确。但是转念一想,我在注释里面写明也可以,这么做有必要吗?
![]() | 1 JCZ2MkKb5S8ZX9pq 2020-03-15 16:55:32 +08:00 可以了解下 assert,不过大多数情况下我是不写的。 |
![]() | 2 westoy 2020-03-15 17:03:31 +08:00 |
3 widewing 2020-03-15 17:10:26 +08:00 via Android def getHTML(url:str): blahblah |
![]() | 4 imn1 2020-03-15 17:16:03 +08:00 按易入难出原则的话,是要写的 但如果都商量好了格式,或者 API 固定,就没必要了 |
![]() | 5 vicalloy 2020-03-15 17:21:59 +08:00 这样做只有运行时才会报错。如果是运行时报错,这个提示不会比不做类型检查的报错清楚多少。 python 3.5 开始支持 type hints,之前的版本也有相应的库支持类似 type hints 的检查。 这样做完全没有必要。 |
![]() | 6 PTLin 2020-03-15 17:26:35 +08:00 真在意类型的话可以用装饰器来实现参数类型的校验,而且 Python 是动态强类型语言。 https://paste.ubuntu.com/p/RSWXVt5pZP/ |
![]() | 7 wuwukai007 2020-03-15 17:27:07 +08:00 写只是为了方便维护,仅此而已。 |
![]() | 8 cmdOptionKana 2020-03-15 17:27:37 +08:00 既然用了 python,建议尽量先习惯一下动态语言的思维方式,曾经盛极一时的 python2 也没有 type hint,照样能干活。 不然多学一门语言有啥意义呢。 (另外你用 type hint, 但你看别人的代码多数没有 type hint, 总的来说还是要转变思维的) |
![]() | 9 ClericPy 2020-03-15 17:46:00 +08:00 ![]() type hints 配合 mypy, 代码没执行就看到一大堆错误类型的报错 type hints 配合 pydantic, 类型不对的会尝试转换, 转换失败会报错, 类似于 var: int = '123' => 123, path: Path = '/' => Path('/') |
![]() | 10 zhengxiaowai 2020-03-15 17:46:52 +08:00 编程理念不同而已,常见的做法有三种 1、利用异常机制自己在错误时候抛出异常,这时候抛出的异常的函数往往不是传入的那个函数,会导致排查困难 2、防御式编程如果你描述的那样,这样代码写的多能够及时发现,排查简单 3、type hint 这个会的不多,写好的更少,依赖工具检查需要高版本 python 从开源项目来看 方式 2 用的比较多,方式 3 是趋势 |
11 ManjusakaL 2020-03-15 18:06:51 +08:00 ![]() 一大堆推荐用 type hint 的,我简直乐的不行 1. Type Hint 3.5 之后的特性,现在还有很多公司的 codebase 在 2.7 吧?拿头用 PEP484 ? 写注释? backport 只支持了基本类型 2. Type Hint 的生效,极其依赖 CI 流程,你不用 mypy 之类的工具,直接暴力上线,有蛋用。。。人家是 static analysis 而不是 runtime analysis 3. 关键位置做防御式编程,是个很好的习惯 |
![]() | 12 ipwx 2020-03-15 18:17:46 +08:00 看情况吧。不过很多一般省去类别检查,就当它是 str 或者 str-like。或者直接 url = str(url)。 |
13 szbzhao 2020-03-15 18:24:25 +08:00 你不要理这些,先把任务完成! |
![]() | 14 janxin 2020-03-15 18:46:03 +08:00 @ManjusakaL 虽然是这么说,但是也要看每个公司的情况,我猜很多用 py2 的大概后面都要换到 Java/Go 去了吧... 另外借助运行时装饰器也是可以实现 runtime checker 功能的,比如 typeguard 之类的工具可以实现这样的功能。当然这种方案也有负面作用,借助 mypy 这类的工具也不是没价值,不过属于额外基础设施方案。 防御编程十分有必要,无论是否是强类型语言,都需要做。 |
![]() | 16 love 2020-03-15 19:09:22 +08:00 那用动态语言又是何必呢 我记得在哪看的 js 最佳实践是不建议写参数类型判断的 |
![]() | 18 shijingshijing 2020-03-15 19:15:32 +08:00 这是 python 的 feature,你这样写就不够 pythonic 了 ![]() |
![]() | 19 love 2020-03-15 19:51:00 +08:00 via Android @janxin 你去看流行的 js 开源代码,没有人会检查参数类型错误。真要检查类型错误上 typescript |
![]() | 20 yuchenyang1994 2020-03-15 19:51:07 +08:00 我看到这些推荐用 type hint 的,我也乐的不行 1. type hint != 类型检查 2. type hint 是自己骗自己,没有编译时的语言,一切类型标注都是自己骗自己,是耍流氓 3. 该写单测写单测 |
![]() | 21 love 2020-03-15 19:53:13 +08:00 via Android @yuchenyang1994 你是来搞笑吗,你的意思是动态类型语言的单元测试还要测试错误的类型输入?哪个项目这么干我去膜拜一下 |
22 jin7 2020-03-15 20:19:20 +08:00 就写个脚本 不用这个复杂.... |
![]() | 23 UnknownR 2020-03-15 20:23:29 +08:00 用 c#,但是理念差不多,try catch 一把梭,报错了再说 要么直接类型转换,转不了再抛出,要么在关键的位置做判断,其他地方等异常抛出了再处理 |
![]() | 24 pabupa 2020-03-15 20:47:08 +08:00 via Android 你不加类型断言,它后面还是会报错的呀…… |
![]() | 25 Applenice 2020-03-15 20:55:36 +08:00 我一般会用 isinstance 去做判断,https://docs.python.org/zh-cn/3/library/functions.html#isinstance |
![]() | 26 keepeye 2020-03-15 21:04:15 +08:00 如果方法是给别人用,那么 1 是要加 type hints,2 是要做必要的类型检测。 自己用的话加个 type hints 就行了,不会明知故犯 |
![]() | 27 yonoho 2020-03-15 21:23:40 +08:00 我们组现在 CR 就强制要求写 type hint。对我们有用吗?有用。对于调用方更易读,对于提供方也迫使他写之前先想清楚,低级错误会少一些。type hint 和 注释的区别在于它的规范性,更容易被支持。比如 Pycharm 就支持这种静态分析,我想也应该有一些好的库可以基于 type hint 实现你的这种需求,只要套一个装饰器就可以了。 |
![]() | 28 noparking188 2020-03-15 21:43:17 +08:00 必要时候我会用 isinstance 类型检查,针对可以设想到的错误场景,大部分时候是不做类型判断的,感觉那太蠢了,多了很多无多大意义的代码,我是做数据开发的,主要处理各种数据,用 py2 之前看了下 fastapi,它用了 pydantic,觉得挺新奇的,比较有意思,不过若是开发有点规模的 web 后台服务,我会选择 java/scala, 虽然我以前上学和实习时候都是用 python 的 flask 框架 个人觉得 type hints 一定程度上可以帮助阅读代码,写的话会带来一些困扰,既然要写明类型,那为什么还要用 Python 呢,或许绝大部分时候并不需要这个特性 个人觉得最好的方式还是协定好开发规范,规范、详细的注释和文档真的很有帮助 一点愚见 |
![]() | 29 noparking188 2020-03-15 21:51:38 +08:00 def getHTML(url): """ fetch html page :param url: :type url: str """ 让它报错,除非你不想这个异常被抛出而中断程序,那么请提前处理 |
![]() | 30 lithbitren 2020-03-15 22:00:52 +08:00 type hints + mypy 可以在运行前解决绝大部分类型问题,这几年 TypeScript 火起来了,Python 也受到了不少影响,不过个人而言还是反对的,类型语言多的是,写 Python 还搞类型就是脱裤子放屁,一点都不 pythonic。 |
31 sepld 2020-03-15 22:04:45 +08:00 可以使用装饰器,定义下接收参数的类型, 提前处理掉 |
![]() | 32 cmdOptionKana 2020-03-15 22:09:24 +08:00 如果必须写 type hint, 那么为啥要用动态类型语言,动态语言被发明出来不就是为了不把类型写死,从而获得一定程度上的便利吗 |
33 zzj0311 2020-03-15 22:25:10 +08:00 via Android 和主流程无关的代码尽量抽离,为了编辑器提示写类型标注就够了 |
![]() | 34 vicalloy 2020-03-15 23:28:22 +08:00 via iPhone 没想到这么多人反对 type hint。 在我看来,对于常用的库 type hint 肯定是趋势。有类型注解,文档都可以少翻很多。 虽然我懒,一般不注明类型,但有时候为了让 ide 的自动补全可以出来也会主动的加上类型注解。 |
![]() | 35 fy 2020-03-15 23:48:23 +08:00 type hint 很有用啊,这玩意是给 IDE 看的呀! |
![]() | 36 pcbl 2020-03-15 23:52:49 +08:00 没有什么事 try except 解决不了的,如果解决不了,那一定是你 try 的不够多(楼上头像) |
![]() | 37 zhidian 2020-03-16 00:15:33 +08:00 type hint 可以让你的 IDE 给你更好的自动补全. |
![]() | 38 metamask 2020-03-16 00:37:29 +08:00 或者你从一个比较高的角度去考虑这个事情, 假如你接受的参数是来自外部或者你必须做强校验,那么你有 2 种更好的选择 - 从 form 或者 serializer 就定义好字段类型 - 自己做一个 validator 这两种做法的好处是,不会让 所谓 “类型”检验的代码散落到处都是 |
![]() | 39 metamask 2020-03-16 00:39:44 +08:00 get_html(url) 这个函数在使用上就默认 url 是一个 str 就好,需要做 validate 之类的话,更有意义是检测它是否是一个完整的 http 链接 |
40 gjquoiai 2020-03-16 01:04:35 +08:00 想写自然可以写,不写也没人逼你写_(:з)∠)_ 突出一个自由。。 不过我觉得你需要的是 serializer/validator 这种东西 |
41 weyou 2020-03-16 01:20:37 +08:00 via Android 这不是应该跟函数的用途有关么?一般写给别人用的接口函数要去 assert 检查下。自己用的内部函数为什么要检查?自己写的函数该提供什么类型的参数自己不知道么?当然在大型项目里你想让自己调试起来方便多加类型判断也是可以的。 |
42 charlie21 2020-03-16 01:38:05 +08:00 知道为什么企业级应用能用 java 就用 java 了吗? |
![]() | 43 yuchenyang1994 2020-03-16 01:50:23 +08:00 @love 运行时报错跟没报有什么区别,我就是要写鸭子类型呢? |
![]() | 44 xingheng 2020-03-16 03:21:16 +08:00 就楼主写的 sample function 而言,加或者不加类型判断都是合理的,调用出错了也不是这个方法本身的错,应该由调用方解决。 类型判断本身是有意义的,比如如果上面方法在实现的时候是接受 str 和 list/tuple 多种数据类型的时候,类型判断就变成了逻辑问题了。 |
![]() | 45 xingheng 2020-03-16 03:30:11 +08:00 不过话说回来 type hint 还是有意义的,python 写多了自然会慢慢发现这个问题。 type hint 本身和类型检查不冲突,但是在使用 typing 或者没有用好 typing 的时候尝试类型检查一定是非常糟心的。 |
46 ManjusakaL 2020-03-16 03:46:52 +08:00 via Android ![]() @janxin yeap 防御式编程非常重要,我只是吐槽一下把 type hint 和防御式编程等价的人。BTW runtime analysis 其实是一件吃力不讨好的事,无论是 typeguard 还是其余库,都避免不了用一些 magic lib 的使用,比如 inspect,比如 typeguard 其中还用到了一些 code frame 的操作,其实在线上一般不太会允许用这样的骚操作,因为对性能的损害太大,虽然 typeguard 有 import hook 可以做一些 inspect 的预处理&缓存的操作(其实就类似编译了)但是实际上在 runtime 还是有很多操作没法避免。。比如 typeguard 对 Collections 对象的 value type 的操作,一旦非 Any,就会遍历一次,进行 check。。在线上数据量很大的情况下。。这是炸锅的节奏 |
![]() | 47 levelworm 2020-03-16 03:47:54 +08:00 via Android type hint 我只是用来增加可读性,这玩意毕竟 Python 并不理睬。 |
![]() | 48 levelworm 2020-03-16 03:49:42 +08:00 via Android 另外楼上有一点说的很对,type hint 对 ide 有帮助,这样自己写代码也快一些。 |
49 ManjusakaL 2020-03-16 04:05:53 +08:00 via iPad |
50 ManjusakaL 2020-03-16 04:31:38 +08:00 @love 如果说上面那个例子是测试结构本身的特性,不严谨的话,那么我肤浅的认为这个 https://github.com/pallets/werkzeug/blob/master/tests/test_routing.py#L802 更能算对输入类型做单测?要求传入 List,否则抛异常 Celery/Django 这样的例子还不少,要不我再去给大佬找几个来请大佬过过目,品一品,评一评? |
51 ManjusakaL 2020-03-16 04:34:42 +08:00 |
52 jjx 2020-03-16 07:51:23 +08:00 type hint 很有意义 用过 typescript 就知道了 不过 python2 的坑 不容易出啊 不知道 python2 还会有更好的方案没有, 在注释中写 这个完全不是一回事情啊 感觉不对 |
![]() | 54 benyur 2020-03-16 07:53:33 +08:00 via Android 我推荐一个思路,如果你是用 python3.5 以上版本,可以看看 pydantic 库,程序员只做类型声明,库帮你做类型检查,其实也是用了 python 的 type hint 特性。 |
![]() | 55 janxin 2020-03-16 08:19:22 +08:00 |
![]() | 57 lithiumii 2020-03-16 08:24:47 +08:00 via Android py 的风格应该是要么不写要么 try except TypeError,要么你就全面 type hint |
![]() | 58 love 2020-03-16 10:09:40 +08:00 via Android @ManjusakaL 你这些不都是业务要求类型检测?为啥不无脑对所有参数检测?你的意思不是要对所有参数检测吗? |
![]() | 59 SteveAlan 2020-03-16 10:19:21 +08:00 via iPhone 要不你去看看 py 一些比较出名的库?看看人家怎么做的 |
![]() | 60 bnm965321 2020-03-16 10:20:30 +08:00 防御性编程是没错的,不过不是每个函数每个参数都要进行防御 |
![]() | 61 vkhsyj 2020-03-16 10:23:20 +08:00 可以用 type hint |
62 iceking 2020-03-16 10:23:40 +08:00 有些场景要做,比如在向 mongo 塞数据时,类型错误就有脏数据了,当然也可以借助 odm 来处理。有的地方你不做,等着程序自己报错,外面捕获也行。要自己定义错误,就自己抛。 |
63 ManjusakaL 2020-03-16 10:35:55 +08:00 via Android |
![]() | 64 Torpedo 2020-03-16 11:13:15 +08:00 还是一定程度上有必要的。特别是你写一个大家都用的模块。传参检测可以防止人家传错误的参数。虽然运行时,至少调试的时候运行到这里可以看到。 |
![]() | 65 tobeyouth 2020-03-16 11:48:24 +08:00 比较复杂的类型建议写上 hints,如果还在 2.7,我觉得注释或通过 schema 验证可能算是个解决方法。 否则,一个嵌套多层的 dict / list,真的太崩溃了。 |
![]() | 66 oahebky 2020-03-16 11:52:45 +08:00 按自己倾向写或者不写。 等你 Python 代码写多了,自然能得到一个到底写还是不写的准确结论。 如果你 python 代码一直没怎么写,那么也不需要去硬遵守应该写或者不写的结论。 因为这个东西无关紧要。有个一年多经常写 Python 代码的人(写的很多的前提下),便可以在需要的地方写,不需要的地方不写。 大多数情况下是不需要写的,当你不确定需不需要写的时候也是不用写的。 |
![]() | 67 TestOpsJarstick 2020-03-16 12:01:35 +08:00 个人觉得得看你得代码主要出路啥业务吧 ,比如你要写一个递归解析多层混合类型 json 数据,一般只有在 debug 的时候才会使用 type() 用得最多的还是 isinstance() |
68 siteshen 2020-03-16 12:10:14 +08:00 @ManjusakaL 1. 坚持用 python 2.x 的用户不是 type hint 的目标用户; 2. type hint 如果是程序员主动发起的话,肯定是会配置一些基础的检查的; 3. type hint 不是万能的,static analysis 比 no analysis 还是好了不少的,最不济还能当个注释,让 ide 能智能补全。 |
69 siteshen 2020-03-16 12:12:19 +08:00 @janxin 可能真的有这种最佳实践,毕竟动态类型语言的优势在于 duck type,即使要判断也应该是判断参数是否实现对应的接口,而不是要求参数是指定的类型。 |
70 ManjusakaL 2020-03-16 12:30:51 +08:00 via Android @siteshen yeap,但是我驳斥的是把 type hint 和防御式编程等价的 |
![]() | 71 pythonee 2020-03-16 15:03:01 +08:00 这个问题每隔一段时间都会问自己吧,就好像选择红药丸和蓝药丸一样 静态语言和动态语言的纠结,写静态语言总是让人更安心些 |
![]() | 72 wzwwzw 2020-03-16 15:11:37 +08:00 在需要的时候写,在不需要的时候不写,如果你不知道这里是不是改写,那就是要写。isinstance 可能是更好的方式。或者使用 pydantic + mypy。 |
![]() | 73 Qzier 2020-03-16 15:16:47 +08:00 via iPhone 具体看需求 |
![]() | 74 fhsan 2020-03-16 15:34:45 +08:00 26.1. typing Support for type hints |
![]() | 76 lewinlan 2020-03-16 23:40:47 +08:00 via Android assert+isinstance,最标准用法。再考虑加函数参数和返回值类型 |
![]() | 77 hushao 2020-04-09 18:15:04 +08:00 即使需要判断也不建议 type,正确的应该用 isinstance |