Python 有必要自己写类型判断吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
onice
V2EX    Python

Python 有必要自己写类型判断吗?

  •  
  •   onice 2020-03-15 16:50:36 +08:00 8788 次点击
    这是一个创建于 2035 天前的主题,其中的信息可能已经有所发展或是发生改变。

    可能是因为我是从 Java 转 Python 的,我把 Python 当作是我的第二语言。

    总所周知,Java 是强类型的语言,传参的时候类型错误编译是不会通过的。

    为了让 Python 能像 Java 那样,我的想法是在方法开始的地方自己手动做类型判断。

    类似这种:

    def getHTML(url): if type(url) != str: raise TypeError("url 参数只能是字符串"") 

    这么做的目的是为了防止传入的参数类型不正确。但是转念一想,我在注释里面写明也可以,这么做有必要吗?

    第 1 条附言    2020-03-16 11:59:32 +08:00
    感谢各位大佬的解答。我觉得快速赋值难道不是 Python 的优势吗,我觉得我是以 Java 编程的思想在去写 Python。
    77 条回复    2020-04-09 18:15:04 +08:00
    JCZ2MkKb5S8ZX9pq
        1
    JCZ2MkKb5S8ZX9pq  
       2020-03-15 16:55:32 +08:00
    可以了解下 assert,不过大多数情况下我是不写的。
    westoy
        2
    westoy  
       2020-03-15 17:03:31 +08:00
    3.5 开始就有 type hints 了啊

    @JCZ2MkKb5S8ZX9pq assert 语法在 python -O 的时候会跳过的, 不是运行时判断的
    widewing
        3
    widewing  
       2020-03-15 17:10:26 +08:00 via Android
    def getHTML(url:str):
    blahblah
    imn1
        4
    imn1  
       2020-03-15 17:16:03 +08:00
    按易入难出原则的话,是要写的
    但如果都商量好了格式,或者 API 固定,就没必要了
    vicalloy
        5
    vicalloy  
       2020-03-15 17:21:59 +08:00
    这样做只有运行时才会报错。如果是运行时报错,这个提示不会比不做类型检查的报错清楚多少。
    python 3.5 开始支持 type hints,之前的版本也有相应的库支持类似 type hints 的检查。
    这样做完全没有必要。
    PTLin
        6
    PTLin  
       2020-03-15 17:26:35 +08:00
    真在意类型的话可以用装饰器来实现参数类型的校验,而且 Python 是动态强类型语言。
    https://paste.ubuntu.com/p/RSWXVt5pZP/
    wuwukai007
        7
    wuwukai007  
       2020-03-15 17:27:07 +08:00
    写只是为了方便维护,仅此而已。
    cmdOptionKana
        8
    cmdOptionKana  
       2020-03-15 17:27:37 +08:00
    既然用了 python,建议尽量先习惯一下动态语言的思维方式,曾经盛极一时的 python2 也没有 type hint,照样能干活。

    不然多学一门语言有啥意义呢。

    (另外你用 type hint, 但你看别人的代码多数没有 type hint, 总的来说还是要转变思维的)
    ClericPy
        9
    ClericPy  
       2020-03-15 17:46:00 +08:00   1
    type hints 配合 mypy, 代码没执行就看到一大堆错误类型的报错

    type hints 配合 pydantic, 类型不对的会尝试转换, 转换失败会报错, 类似于 var: int = '123' => 123, path: Path = '/' => Path('/')
    zhengxiaowai
        10
    zhengxiaowai  
       2020-03-15 17:46:52 +08:00
    编程理念不同而已,常见的做法有三种

    1、利用异常机制自己在错误时候抛出异常,这时候抛出的异常的函数往往不是传入的那个函数,会导致排查困难
    2、防御式编程如果你描述的那样,这样代码写的多能够及时发现,排查简单
    3、type hint 这个会的不多,写好的更少,依赖工具检查需要高版本 python

    从开源项目来看 方式 2 用的比较多,方式 3 是趋势
    ManjusakaL
        11
    ManjusakaL  
       2020-03-15 18:06:51 +08:00   5
    一大堆推荐用 type hint 的,我简直乐的不行

    1. Type Hint 3.5 之后的特性,现在还有很多公司的 codebase 在 2.7 吧?拿头用 PEP484 ? 写注释? backport 只支持了基本类型

    2. Type Hint 的生效,极其依赖 CI 流程,你不用 mypy 之类的工具,直接暴力上线,有蛋用。。。人家是 static analysis 而不是 runtime analysis

    3. 关键位置做防御式编程,是个很好的习惯
    ipwx
        12
    ipwx  
       2020-03-15 18:17:46 +08:00
    看情况吧。不过很多一般省去类别检查,就当它是 str 或者 str-like。或者直接 url = str(url)。
    szbzhao
        13
    szbzhao  
       2020-03-15 18:24:25 +08:00
    你不要理这些,先把任务完成!
    janxin
        14
    janxin  
       2020-03-15 18:46:03 +08:00
    @ManjusakaL 虽然是这么说,但是也要看每个公司的情况,我猜很多用 py2 的大概后面都要换到 Java/Go 去了吧...

    另外借助运行时装饰器也是可以实现 runtime checker 功能的,比如 typeguard 之类的工具可以实现这样的功能。当然这种方案也有负面作用,借助 mypy 这类的工具也不是没价值,不过属于额外基础设施方案。

    防御编程十分有必要,无论是否是强类型语言,都需要做。
    iConnect
        15
    iConnect  
       2020-03-15 18:55:29 +08:00
    @ipwx #12 楼的方式值得推荐,关键位置预防一下即可。
    love
        16
    love  
       2020-03-15 19:09:22 +08:00
    那用动态语言又是何必呢
    我记得在哪看的 js 最佳实践是不建议写参数类型判断的
    janxin
        17
    janxin  
       2020-03-15 19:11:08 +08:00
    @love 还有这种实践?我读书少你别骗我
    shijingshijing
        18
    shijingshijing  
       2020-03-15 19:15:32 +08:00
    这是 python 的 feature,你这样写就不够 pythonic 了
    love
        19
    love  
       2020-03-15 19:51:00 +08:00 via Android
    @janxin 你去看流行的 js 开源代码,没有人会检查参数类型错误。真要检查类型错误上 typescript
    yuchenyang1994
        20
    yuchenyang1994  
       2020-03-15 19:51:07 +08:00
    我看到这些推荐用 type hint 的,我也乐的不行
    1. type hint != 类型检查
    2. type hint 是自己骗自己,没有编译时的语言,一切类型标注都是自己骗自己,是耍流氓
    3. 该写单测写单测
    love
        21
    love  
       2020-03-15 19:53:13 +08:00 via Android
    @yuchenyang1994 你是来搞笑吗,你的意思是动态类型语言的单元测试还要测试错误的类型输入?哪个项目这么干我去膜拜一下
    jin7
        22
    jin7  
       2020-03-15 20:19:20 +08:00
    就写个脚本 不用这个复杂....
    UnknownR
        23
    UnknownR  
       2020-03-15 20:23:29 +08:00
    用 c#,但是理念差不多,try catch 一把梭,报错了再说

    要么直接类型转换,转不了再抛出,要么在关键的位置做判断,其他地方等异常抛出了再处理
    pabupa
        24
    pabupa  
       2020-03-15 20:47:08 +08:00 via Android
    你不加类型断言,它后面还是会报错的呀……
    Applenice
        25
    Applenice  
       2020-03-15 20:55:36 +08:00
    keepeye
        26
    keepeye  
       2020-03-15 21:04:15 +08:00
    如果方法是给别人用,那么 1 是要加 type hints,2 是要做必要的类型检测。
    自己用的话加个 type hints 就行了,不会明知故犯
    yonoho
        27
    yonoho  
       2020-03-15 21:23:40 +08:00
    我们组现在 CR 就强制要求写 type hint。对我们有用吗?有用。对于调用方更易读,对于提供方也迫使他写之前先想清楚,低级错误会少一些。type hint 和 注释的区别在于它的规范性,更容易被支持。比如 Pycharm 就支持这种静态分析,我想也应该有一些好的库可以基于 type hint 实现你的这种需求,只要套一个装饰器就可以了。
    noparking188
        28
    noparking188  
       2020-03-15 21:43:17 +08:00
    必要时候我会用 isinstance 类型检查,针对可以设想到的错误场景,大部分时候是不做类型判断的,感觉那太蠢了,多了很多无多大意义的代码,我是做数据开发的,主要处理各种数据,用 py2
    之前看了下 fastapi,它用了 pydantic,觉得挺新奇的,比较有意思,不过若是开发有点规模的 web 后台服务,我会选择 java/scala, 虽然我以前上学和实习时候都是用 python 的 flask 框架
    个人觉得 type hints 一定程度上可以帮助阅读代码,写的话会带来一些困扰,既然要写明类型,那为什么还要用 Python 呢,或许绝大部分时候并不需要这个特性
    个人觉得最好的方式还是协定好开发规范,规范、详细的注释和文档真的很有帮助
    一点愚见
    noparking188
        29
    noparking188  
       2020-03-15 21:51:38 +08:00
    def getHTML(url):
    """ fetch html page

    :param url:
    :type url: str
    """

    让它报错,除非你不想这个异常被抛出而中断程序,那么请提前处理
    lithbitren
        30
    lithbitren  
       2020-03-15 22:00:52 +08:00
    type hints + mypy 可以在运行前解决绝大部分类型问题,这几年 TypeScript 火起来了,Python 也受到了不少影响,不过个人而言还是反对的,类型语言多的是,写 Python 还搞类型就是脱裤子放屁,一点都不 pythonic。
    sepld
        31
    sepld  
       2020-03-15 22:04:45 +08:00
    可以使用装饰器,定义下接收参数的类型, 提前处理掉
    cmdOptionKana
        32
    cmdOptionKana  
       2020-03-15 22:09:24 +08:00
    如果必须写 type hint, 那么为啥要用动态类型语言,动态语言被发明出来不就是为了不把类型写死,从而获得一定程度上的便利吗
    zzj0311
        33
    zzj0311  
       2020-03-15 22:25:10 +08:00 via Android
    和主流程无关的代码尽量抽离,为了编辑器提示写类型标注就够了
    vicalloy
        34
    vicalloy  
       2020-03-15 23:28:22 +08:00 via iPhone
    没想到这么多人反对 type hint。
    在我看来,对于常用的库 type hint 肯定是趋势。有类型注解,文档都可以少翻很多。
    虽然我懒,一般不注明类型,但有时候为了让 ide 的自动补全可以出来也会主动的加上类型注解。
    fy
        35
    fy  
       2020-03-15 23:48:23 +08:00
    type hint 很有用啊,这玩意是给 IDE 看的呀!
    pcbl
        36
    pcbl  
       2020-03-15 23:52:49 +08:00
    没有什么事 try except 解决不了的,如果解决不了,那一定是你 try 的不够多(楼上头像)
    zhidian
        37
    zhidian  
       2020-03-16 00:15:33 +08:00
    type hint 可以让你的 IDE 给你更好的自动补全.
    metamask
        38
    metamask  
       2020-03-16 00:37:29 +08:00
    或者你从一个比较高的角度去考虑这个事情,

    假如你接受的参数是来自外部或者你必须做强校验,那么你有 2 种更好的选择

    - 从 form 或者 serializer 就定义好字段类型
    - 自己做一个 validator

    这两种做法的好处是,不会让 所谓 “类型”检验的代码散落到处都是
    metamask
        39
    metamask  
       2020-03-16 00:39:44 +08:00
    get_html(url)

    这个函数在使用上就默认 url 是一个 str 就好,需要做 validate 之类的话,更有意义是检测它是否是一个完整的 http 链接
    gjquoiai
        40
    gjquoiai  
       2020-03-16 01:04:35 +08:00
    想写自然可以写,不写也没人逼你写_(:з)∠)_ 突出一个自由。。
    不过我觉得你需要的是 serializer/validator 这种东西
    weyou
        41
    weyou  
       2020-03-16 01:20:37 +08:00 via Android
    这不是应该跟函数的用途有关么?一般写给别人用的接口函数要去 assert 检查下。自己用的内部函数为什么要检查?自己写的函数该提供什么类型的参数自己不知道么?当然在大型项目里你想让自己调试起来方便多加类型判断也是可以的。
    charlie21
        42
    charlie21  
       2020-03-16 01:38:05 +08:00
    知道为什么企业级应用能用 java 就用 java 了吗?
    yuchenyang1994
        43
    yuchenyang1994  
       2020-03-16 01:50:23 +08:00
    @love 运行时报错跟没报有什么区别,我就是要写鸭子类型呢?
    xingheng
        44
    xingheng  
       2020-03-16 03:21:16 +08:00
    就楼主写的 sample function 而言,加或者不加类型判断都是合理的,调用出错了也不是这个方法本身的错,应该由调用方解决。
    类型判断本身是有意义的,比如如果上面方法在实现的时候是接受 str 和 list/tuple 多种数据类型的时候,类型判断就变成了逻辑问题了。
    xingheng
        45
    xingheng  
       2020-03-16 03:30:11 +08:00
    不过话说回来 type hint 还是有意义的,python 写多了自然会慢慢发现这个问题。
    type hint 本身和类型检查不冲突,但是在使用 typing 或者没有用好 typing 的时候尝试类型检查一定是非常糟心的。
    ManjusakaL
        46
    ManjusakaL  
       2020-03-16 03:46:52 +08:00 via Android   1
    @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。。在线上数据量很大的情况下。。这是炸锅的节奏
    levelworm
        47
    levelworm  
       2020-03-16 03:47:54 +08:00 via Android
    type hint 我只是用来增加可读性,这玩意毕竟 Python 并不理睬。
    levelworm
        48
    levelworm  
       2020-03-16 03:49:42 +08:00 via Android
    另外楼上有一点说的很对,type hint 对 ide 有帮助,这样自己写代码也快一些。
    ManjusakaL
        49
    ManjusakaL  
       2020-03-16 04:05:53 +08:00 via iPad
    ManjusakaL
        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 这样的例子还不少,要不我再去给大佬找几个来请大佬过过目,品一品,评一评?
    ManjusakaL
        51
    ManjusakaL  
       2020-03-16 04:34:42 +08:00
    jjx
        52
    jjx  
       2020-03-16 07:51:23 +08:00
    type hint 很有意义

    用过 typescript 就知道了

    不过 python2 的坑 不容易出啊

    不知道 python2 还会有更好的方案没有, 在注释中写 这个完全不是一回事情啊 感觉不对
    Trim21
        53
    Trim21  
       2020-03-16 07:52:58 +08:00 via iPhone
    @jjx 是不是可以写 pyi…
    benyur
        54
    benyur  
       2020-03-16 07:53:33 +08:00 via Android
    我推荐一个思路,如果你是用 python3.5 以上版本,可以看看 pydantic 库,程序员只做类型声明,库帮你做类型检查,其实也是用了 python 的 type hint 特性。
    janxin
        55
    janxin  
       2020-03-16 08:19:22 +08:00
    @ManjusakaL 起床过于早了啊....

    确实性能退化是最大的负面作用,选择需要根据具体的情况进行取舍
    RHxW
        56
    RHxW  
       2020-03-16 08:23:15 +08:00
    @benyur
    这个东西看起来好像很 6 哦~
    lithiumii
        57
    lithiumii  
       2020-03-16 08:24:47 +08:00 via Android
    py 的风格应该是要么不写要么 try except TypeError,要么你就全面 type hint
    love
        58
    love  
       2020-03-16 10:09:40 +08:00 via Android
    @ManjusakaL 你这些不都是业务要求类型检测?为啥不无脑对所有参数检测?你的意思不是要对所有参数检测吗?
    SteveAlan
        59
    SteveAlan  
       2020-03-16 10:19:21 +08:00 via iPhone
    要不你去看看 py 一些比较出名的库?看看人家怎么做的
    bnm965321
        60
    bnm965321  
       2020-03-16 10:20:30 +08:00
    防御性编程是没错的,不过不是每个函数每个参数都要进行防御
    vkhsyj
        61
    vkhsyj  
       2020-03-16 10:23:20 +08:00
    可以用 type hint
    iceking
        62
    iceking  
       2020-03-16 10:23:40 +08:00
    有些场景要做,比如在向 mongo 塞数据时,类型错误就有脏数据了,当然也可以借助 odm 来处理。有的地方你不做,等着程序自己报错,外面捕获也行。要自己定义错误,就自己抛。
    ManjusakaL
        63
    ManjusakaL  
       2020-03-16 10:35:55 +08:00 via Android
    @love 大佬你之前可不是这么说的噢

    > 你是来搞笑吗,你的意思是动态类型语言的单元测试还要测试错误的类型输入?哪个项目这么干我去膜拜一下

    这不给你找了几个项目嘛
    Torpedo
        64
    Torpedo  
       2020-03-16 11:13:15 +08:00
    还是一定程度上有必要的。特别是你写一个大家都用的模块。传参检测可以防止人家传错误的参数。虽然运行时,至少调试的时候运行到这里可以看到。
    tobeyouth
        65
    tobeyouth  
       2020-03-16 11:48:24 +08:00
    比较复杂的类型建议写上 hints,如果还在 2.7,我觉得注释或通过 schema 验证可能算是个解决方法。
    否则,一个嵌套多层的 dict / list,真的太崩溃了。
    oahebky
        66
    oahebky  
       2020-03-16 11:52:45 +08:00
    按自己倾向写或者不写。
    等你 Python 代码写多了,自然能得到一个到底写还是不写的准确结论。
    如果你 python 代码一直没怎么写,那么也不需要去硬遵守应该写或者不写的结论。

    因为这个东西无关紧要。有个一年多经常写 Python 代码的人(写的很多的前提下),便可以在需要的地方写,不需要的地方不写。
    大多数情况下是不需要写的,当你不确定需不需要写的时候也是不用写的。
    TestOpsJarstick
        67
    TestOpsJarstick  
       2020-03-16 12:01:35 +08:00
    个人觉得得看你得代码主要出路啥业务吧 ,比如你要写一个递归解析多层混合类型 json 数据,一般只有在 debug 的时候才会使用 type() 用得最多的还是 isinstance()
    siteshen
        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 能智能补全。
    siteshen
        69
    siteshen  
       2020-03-16 12:12:19 +08:00
    @janxin 可能真的有这种最佳实践,毕竟动态类型语言的优势在于 duck type,即使要判断也应该是判断参数是否实现对应的接口,而不是要求参数是指定的类型。
    ManjusakaL
        70
    ManjusakaL  
       2020-03-16 12:30:51 +08:00 via Android
    @siteshen yeap,但是我驳斥的是把 type hint 和防御式编程等价的
    pythonee
        71
    pythonee  
       2020-03-16 15:03:01 +08:00
    这个问题每隔一段时间都会问自己吧,就好像选择红药丸和蓝药丸一样
    静态语言和动态语言的纠结,写静态语言总是让人更安心些
    wzwwzw
        72
    wzwwzw  
       2020-03-16 15:11:37 +08:00
    在需要的时候写,在不需要的时候不写,如果你不知道这里是不是改写,那就是要写。isinstance 可能是更好的方式。或者使用 pydantic + mypy。
    Qzier
        73
    Qzier  
       2020-03-16 15:16:47 +08:00 via iPhone
    具体看需求
    fhsan
        74
    fhsan  
       2020-03-16 15:34:45 +08:00
    26.1. typing Support for type hints
    janxin
        75
    janxin  
       2020-03-16 16:01:10 +08:00
    @siteshen duck type 在类型标注里也有对应的啊...
    lewinlan
        76
    lewinlan  
       2020-03-16 23:40:47 +08:00 via Android
    assert+isinstance,最标准用法。再考虑加函数参数和返回值类型
    hushao
        77
    hushao  
       2020-04-09 18:15:04 +08:00
    即使需要判断也不建议 type,正确的应该用 isinstance
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3366 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 00:18 PVG 08:18 LAX 17:18 JFK 20:18
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86