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

2018-07-25 23:45:42 +08:00
 Philippa

比如说:

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 和记忆力还有什么好办法?

4447 次点击
所在节点    Python
17 条回复
Tyanboot
2018-07-26 00:13:05 +08:00
类型标注这个只有在 3.6 及以上的版本才支持的. 解决办法就是升级你的 python 到 3.6
so1n
2018-07-26 00:32:47 +08:00
有个叫 attrs 的库
ligyxy
2018-07-26 01:12:26 +08:00
Data Classes
Cbdy
2018-07-26 08:25:22 +08:00
换有类型的语言
araraloren
2018-07-26 08:51:54 +08:00
可选类型的语言是多么明智。。
netfee
2018-07-26 09:40:26 +08:00
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
2018-07-26 09:59:52 +08:00
换语言
xpresslink
2018-07-26 10:05:45 +08:00
有个比较 lowbility 但是有效的办法就是,在函数或类最开始
就把要用到所有变量名加上类型前缀或后缀并赋初始值,比如下面这样:
def foo():
int_a = 0,
a_int=0 ,
str_b='',
b_str=''

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

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

或者不用在意类型,用的时候强制转换就行了…比如这个 age,你先 age = int(p.age)不就完了
Philippa
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
2018-07-26 11:49:55 +08:00
为什么 markdown 不能用……
Philippa
2018-07-26 11:51:43 +08:00
可以在 class 里面加入一个参数, 虽然有点不雅观,mutable -> bool 来决定是否 mutable。一样地,在__setattr__里面做检查。
Philippa
2018-07-26 11:54:55 +08:00
@xpresslink 换语言不是说换就换了,写 numpy 的话 golang 怎么写…… postfix 加类型的做法已经实行很久了,但效果有限,尤其对镶嵌类型的 list 等,numpy 有太多自定义类型,然而 python 本身却不可标注,再加上镶嵌,灾难就发生了
Philippa
2018-07-26 11:57:08 +08:00
@karllynn 每次都 int(age)这样太丑了,妨碍其他人阅读你的代码,code review 肯定不让过,而且影响性能(虽说不大)。
GoLand
2018-07-26 13:03:18 +08:00
pydantic 了解一下。还有校验功能。结合 mypy 使用。
Philippa
2018-07-26 14:04:43 +08:00
@GoLand 谢谢,这个库有些有用的工具可以用来自己封装。因为测试后发现,初始化为 str 后赋予 int 还是不会抛 error。当传入错误的类型,希望程序能够崩溃。
linkermlin
2018-11-19 18:10:16 +08:00
不编译检查了又能怎么样呢?
还是 Cython 靠谱。推荐了解下。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/474197

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX