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
Philippa
V2EX  ›  Python

Python 的类的类型标注有什么好的方案?

  •  
  •   Philippa · 2018-07-25 23:45:42 +08:00 · 4442 次点击
    这是一个创建于 2311 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如说:

    import numpy as np
    
    class Person:
        name: str
        age: int
        hobbies: np.ndarray
       
    person = Person()
    person.age = "12" # raise TypeMismatched exception
    

    Github 上面找到几个在 Python3 测试一下然而并不能用。现在开发 debug 中遇到的 10 个 需要呕心沥血 debug 的中有 9 个都是因为类型问题,镶嵌类型尤其难搞。def 虽然有 type hints,但是函数过多时会封装成这样:

    class Params:
        param1 = 'hello'
        param2 = '...'
        ...
        param7 = '...'
    

    所以为了保持代码干净,最好还是在 class 里加入类型的检查。大家除了 IDE、眼球 parse 和记忆力还有什么好办法?

    17 条回复    2018-11-19 18:10:16 +08:00
    Tyanboot
        1
    Tyanboot  
       2018-07-26 00:13:05 +08:00
    类型标注这个只有在 3.6 及以上的版本才支持的. 解决办法就是升级你的 python 到 3.6
    so1n
        2
    so1n  
       2018-07-26 00:32:47 +08:00 via Android   ❤️ 1
    有个叫 attrs 的库
    ligyxy
        3
    ligyxy  
       2018-07-26 01:12:26 +08:00 via Android
    Data Classes
    Cbdy
        4
    Cbdy  
       2018-07-26 08:25:22 +08:00 via Android
    换有类型的语言
    araraloren
        5
    araraloren  
       2018-07-26 08:51:54 +08:00
    可选类型的语言是多么明智。。
    netfee
        6
    netfee  
       2018-07-26 09:40:26 +08:00 via Android   ❤️ 1
    class People:
    def __init_(self, name: str=None, age: int=0) ->None:
    ---

    def find_all_people() ->[People]:
    ---

    这样实现类型注释,方便 ide 预检查错误,参考
    pep 484 type hint
    https://www.python.org/dev/peps/pep-0484/
    Python 3.5 就提供这种语法支持了。而当前主流 Linux 发行版预置的 Python3 都是 3.5+以上版本了,所以真的可以全面转到 py3 了。到 V3.6 还提供 f-string 语句支持( pep 498 )。
    zhuangzhuang1988
        7
    zhuangzhuang1988  
       2018-07-26 09:59:52 +08:00
    换语言
    xpresslink
        8
    xpresslink  
       2018-07-26 10:05:45 +08:00   ❤️ 1
    有个比较 lowbility 但是有效的办法就是,在函数或类最开始
    就把要用到所有变量名加上类型前缀或后缀并赋初始值,比如下面这样:
    def foo():
    int_a = 0,
    a_int=0 ,
    str_b='',
    b_str=''

    过程中严禁同一变量名改换类型使用,这样 IDE 就可以比较好的类型推断了。

    不过这样写 python 的话还不如直接用够浪( golang )
    karllynn
        9
    karllynn  
       2018-07-26 11:20:25 +08:00
    升级到最新的 Python

    或者不用在意类型,用的时候强制转换就行了…比如这个 age,你先 age = int(p.age)不就完了
    Philippa
        10
    Philippa  
    OP
       2018-07-26 11:48:50 +08:00
    当把 object 作为参数时,python3.6 是不能检查 object 的 attr 的类型的。变量名包括类型已经有了,然而变量多层传递后也不会有大的作用。因此:

    ```
    class Person:
    name: str
    age: int

    ```
    以上这种语法是无效的,Python3.6 也根本不支持这种语法,我不知道大家回答这个是因为误解了还是不知道这一点。
    但下面这一个可以。

    ```
    class TypeMismatched(Exception):
    pass

    class Person:

    def __init__(self, name: str, age: int):
    self.name = name
    self.age = age

    def __setattr__(self, name, value):
    # Invalid for class comparsion
    if hasattr(self, name) and type(self.__dict__[name]) != type(value):
    raise TypeMismatched
    self.__dict__[name] = value

    person = Person(name='Jane', age=12)
    print(person.name)
    print(person.age)
    person.age = '14'
    print(person.age) # raise TypeMismatched Exception

    ```
    因此想了想,用 type hints 作为 class 属性的首次检查,重载__setattr__,加入检查方法,作为以后 mutable 值的检查。上面的 type(variable_a) == type(variavble_b)有缺陷,需要再改进一下,但基本思路就这样了。
    Philippa
        11
    Philippa  
    OP
       2018-07-26 11:49:55 +08:00
    为什么 markdown 不能用……
    Philippa
        12
    Philippa  
    OP
       2018-07-26 11:51:43 +08:00
    可以在 class 里面加入一个参数, 虽然有点不雅观,mutable -> bool 来决定是否 mutable。一样地,在__setattr__里面做检查。
    Philippa
        13
    Philippa  
    OP
       2018-07-26 11:54:55 +08:00
    @xpresslink 换语言不是说换就换了,写 numpy 的话 golang 怎么写…… postfix 加类型的做法已经实行很久了,但效果有限,尤其对镶嵌类型的 list 等,numpy 有太多自定义类型,然而 python 本身却不可标注,再加上镶嵌,灾难就发生了
    Philippa
        14
    Philippa  
    OP
       2018-07-26 11:57:08 +08:00
    @karllynn 每次都 int(age)这样太丑了,妨碍其他人阅读你的代码,code review 肯定不让过,而且影响性能(虽说不大)。
    GoLand
        15
    GoLand  
       2018-07-26 13:03:18 +08:00   ❤️ 1
    pydantic 了解一下。还有校验功能。结合 mypy 使用。
    Philippa
        16
    Philippa  
    OP
       2018-07-26 14:04:43 +08:00
    @GoLand 谢谢,这个库有些有用的工具可以用来自己封装。因为测试后发现,初始化为 str 后赋予 int 还是不会抛 error。当传入错误的类型,希望程序能够崩溃。
    linkermlin
        17
    linkermlin  
       2018-11-19 18:10:16 +08:00
    不编译检查了又能怎么样呢?
    还是 Cython 靠谱。推荐了解下。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4590 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 01:06 · PVG 09:06 · LAX 17:06 · JFK 20:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.