Ott*_*tto 27 python static-typing typescript mypy
最近我一直在使用Typescript,它允许表达如下内容:
interface Address {
street: string;
housenumber: number;
housenumberPostfix?: string;
}
interface Person {
name: string;
adresses: Address[]
}
const person: Person = {
name: 'Joe',
adresses: [
{ street: 'Sesame', housenumber: 1 },
{ street: 'Baker', housenumber: 221, housenumberPostfix: 'b' }
]
}
Run Code Online (Sandbox Code Playgroud)
非常简洁,并在使用人员编码时将所有奢侈品作为类型检查和代码完成.
这是如何在Python中完成的?
我一直在看Mypy和ABC但是还没有成功找到pythonic方式做类似上面的事情(我的尝试导致了太多的样板符合我的口味).
hoe*_*ing 19
对于IDE中的代码完成和类型提示,只需为Person
和Address
类添加静态类型,您已经很好了.假设你使用最新的python3.6
,这里是你的例子中的typescript类的粗略等价物:
# spam.py
from typing import Optional, Sequence
class Address:
street: str
housenumber: int
housenumber_postfix: Optional[str]
def __init__(self, street: str, housenumber: int,
housenumber_postfix: Optional[str] = None) -> None:
self.street = street
self.housenumber = housenumber
self.housenumber_postfix = housenumber_postfix
class Person:
name: str
adresses: Sequence[Address]
def __init__(self, name: str, adresses: Sequence[str]) -> None:
self.name = name
self.adresses = adresses
person = Person('Joe', [
Address('Sesame', 1),
Address('Baker', 221, housenumber_postfix='b')
]) # type: Person
Run Code Online (Sandbox Code Playgroud)
我想在添加类构造函数时会出现你提到的样板文件.这确实是不可避免的.我希望默认构造函数是在未明确声明时在运行时生成的,如下所示:
class Address:
street: str
housenumber: int
housenumber_postfix: Optional[str]
class Person:
name: str
adresses: Sequence[Address]
if __name__ == '__main__':
alice = Person('Alice', [Address('spam', 1, housenumber_postfix='eggs')])
bob = Person('Bob', ()) # a tuple is also a sequence
Run Code Online (Sandbox Code Playgroud)
但不幸的是你必须手动声明它们.
正如Michael0x2a在注释中指出的那样,对于默认构造函数的需求是可以避免的,python3.7
其中引入了一个@dataclass
装饰器,所以人们确实可以声明:
@dataclass
class Address:
street: str
housenumber: int
housenumber_postfix: Optional[str]
@dataclass
class Person:
name: str
adresses: Sequence[Address]
Run Code Online (Sandbox Code Playgroud)
并获得几种方法的默认impl,减少样板代码的数量.查看PEP 557了解更多详情.
我想你可以看到可以从你的代码生成的存根文件,作为某种接口文件:
$ stubgen spam # stubgen tool is part of mypy package
Created out/spam.pyi
Run Code Online (Sandbox Code Playgroud)
生成的存根文件包含所有非私有类的类型签名和模块的功能,而不实现:
# Stubs for spam (Python 3.6)
#
# NOTE: This dynamically typed stub was automatically generated by stubgen.
from typing import Optional, Sequence
class Address:
street: str
housenumber: int
housenumber_postfix: Optional[str]
def __init__(self, street: str, housenumber: int, housenumber_postfix: Optional[str]=...) -> None: ...
class Person:
name: str
adresses: Sequence[Address]
def __init__(self, name: str, adresses: Sequence[str]) -> None: ...
person: Person
Run Code Online (Sandbox Code Playgroud)
这些存根文件也可以被IDE识别,如果您的原始模块没有静态类型,它们将使用存根文件进行类型提示和代码完成.
我发现一个简单的解决方案(不需要 Python 3.7)是使用SimpleNamespace:
from types import SimpleNamespace as NS
from typing import Optional, List
class Address(NS):
street: str
housenumber: int
housenumber_postfix: Optional[str]=None
class Person(NS):
name: str
addresses: List[Address]
person = Person(
name='Joe',
addresses=[
Address(street='Sesame', housenumber=1),
Address(street='Baker', housenumber=221, housenumber_postfix='b')
])
Run Code Online (Sandbox Code Playgroud)
person.name = 1
如果有人能指出为什么 Python 3.7 的dataclass
装饰器会更好,我很乐意听到。
TypeScript 接口描述了一个 JavaScript 对象。这样的对象类似于具有众所周知的字符串键的 Python 字典,它由 mypy TypedDict描述。
例如 TypeScript 接口:
interface Address {
street: string;
housenumber: number;
}
Run Code Online (Sandbox Code Playgroud)
将描述 JavaScript 对象,如:
var someAddress = {
street: 'SW Gemini Dr.',
housenumber: 9450,
};
Run Code Online (Sandbox Code Playgroud)
等效的 mypy TypedDict
:
from typing_extensions import TypedDict
class Address(TypedDict):
street: str
housenumber: int
Run Code Online (Sandbox Code Playgroud)
将描述 Python 字典,如:
some_address = {
'street': 'SW Gemini Dr.',
'housenumber': 9450,
}
# or equivalently:
some_address = dict(
street='SW Gemini Dr.',
housenumber=9450,
)
Run Code Online (Sandbox Code Playgroud)
这些字典可以简单地与 JSON 序列化,并将符合类似的 TypeScript 接口类型。
注意:如果您使用的是 Python 2 或更旧版本的 Python 3,您可能需要对 TypedDict 使用旧的基于函数的语法:
from mypy_extensions import TypedDict
Address = TypedDict('Address', {
'street': str,
'housenumber': int,
})
Run Code Online (Sandbox Code Playgroud)
Python 中还有其他方法来表示具有命名属性的结构。
命名元组很便宜并且具有只读键。但是,它们不能自动序列化为 JSON 或从 JSON 序列化。
from typing import NamedTuple
class Address(NamedTuple):
street: str
housenumber: int
my_address = Address(
street='SW Gemini Dr.',
housenumber=9450,
)
Run Code Online (Sandbox Code Playgroud)
在 Python 3.7 中可用的数据类具有读写键。它们也不能自动序列化为 JSON 或从 JSON 序列化。
from dataclasses import dataclass
@dataclass
class Address:
street: str
housenumber: int
my_address = Address(
street='SW Gemini Dr.',
housenumber=9450,
)
Run Code Online (Sandbox Code Playgroud)
Python 3.3 中提供的简单命名空间与数据类类似,但不是很出名。
from types import SimpleNamespace
class Address(SimpleNamespace):
street: str
housenumber: int
my_address = Address(
street='SW Gemini Dr.',
housenumber=9450,
)
Run Code Online (Sandbox Code Playgroud)
attrs是一个长期存在的第三方库,类似于数据类,但具有更多功能。attrs 被 mypy typechecker 识别。
import attrs
@attr.s(auto_attribs=True)
class Address:
street: str
housenumber: int
my_address = Address(
street='SW Gemini Dr.',
housenumber=9450,
)
Run Code Online (Sandbox Code Playgroud)
Python 3.6添加了一个可以处理类型提示的namedtuple新实现,从而删除了其他答案所需的一些样板。
from typing import NamedTuple, Optional, List
class Address(NamedTuple):
street: str
housenumber: int
housenumberPostfix: Optional[str] = None
class Person(NamedTuple):
name: str
adresses: List[Address]
person = Person(
name='Joe',
adresses=[
Address(street='Sesame', housenumber=1),
Address(street='Baker', housenumber=221, housenumberPostfix='b'),
],
)
Run Code Online (Sandbox Code Playgroud)
编辑:NamedTuple
s是不可变的,因此请注意,如果要修改对象的字段,则不能使用此解决方案。更改的内容lists
,并dicts
仍然有效。
也许这会很好地与 mypy
from typing import List
from mypy_extensions import TypedDict
EntityAndMeta = TypedDict("EntityAndMeta", {"name": str, "count": int})
my_list: List[EntityAndMeta] = [
{"name": "Amy", "count": 17},
{"name": "Bob", "count": 42},
]
Run Code Online (Sandbox Code Playgroud)
从mypy 文档或源代码中阅读有关TypedDict 的更多信息
我很确定你可以嵌套这些东西,Optional
如果你愿意,可以设置其中的一些。
我从/sf/answers/1471040441/得到这个想法
归档时间: |
|
查看次数: |
7719 次 |
最近记录: |