函数和类的类型和主题检查。
strict的Python项目详细描述
strict是一个模块,它解决了类型签入的常见需要 Python。
快速示例
功能约束
向函数签名添加类型约束:
from __future__ import print_function from strict.functions import * @expects(arg(float), arg(float), message=arg(str)) def multiply_and_print(a, b, message="You've got {result}"): print(message.format(result=(a * b))) # This works just fine multiply_and_print(2.0, 3.0) # This raises a TypeConstraintError multiply_and_print(int(2.0), 3.0)
向方法添加类型约束:
from __future__ import print_function from strict.functions import * class Foo(object): @expects(self, arg(str)) def __init__(self, name): self.name = name def say_hello(self): print(", ".join(["Hello", self.name])) # This works f = Foo("Jim") f.say_hello() # This doesn't f = Foo(123) f.say_hello()
对函数的返回值添加约束:
from strict.functions import * @returns(int) def return_two(): return 2 @returns(int) def return_half(): return 0.5 # This works fine return_two() # This raises an exception return_half()
向函数添加主题约束和类型约束:
@expects(arg(float), arg(float, lambda x: x != 0)) def divide(a, b): "We need to make sure, that b isn't zero..." return a / b # This works divide(4.0, 2.0) # This all fails with a TypeConstraintError divide(4, 2.0) divide(4.0, "poop") # This fails with a SubjectConstraintError divide(4.0, 0.0)
结构
定义结构:
from strict.structures import * class Point(Structure): """ Let's have a point, that can fit only on a certain area. """ x = Field(float, lambda x: 0.0 < x < 1000.0) y = Field(float, lambda y: 0.0 < y < 1000.0) def __init__(self, x, y): self.x = x self.y = y # This works a = Point(10.0, 15.0) # This all fails with the correct exception Point(10, 15) Point(10.0, 1001.0) Point(-2.0, 50.0)
序列化结构:
from strict.structures import * class Point(Structure): """ Let's have a point, that can fit only on a certain area. """ x = Field(float, lambda x: 0.0 < x < 1000.0) y = Field(float, lambda y: 0.0 < y < 1000.0) def __init__(self, x, y): self.x = x self.y = y a = Point(10.0, 15.0) # This outputs a dictionary a.to_dict() # This outputs a list a.to_list()
我为什么要打支票?
尽管如此,在python中处理类型兼容性问题的常用习惯用法是 鸭子打字,在某些情况下是不够的。
关于usage context的信息通常隐式编码在 类名,duck类型通常无法处理,除非 引入迥然不同的类接口,或者仅仅引入kludge
考虑一下财务应用程序的以下类树:
+--------------------------+ | | | BaseVolatilitySurface | | | +-------------+------------+ | | | | +---------------------------+ | +-------------------------+ | | | | | | EquityVolatilitySurface <-----+-----> RateVolatilitySurface | | | | | +---------------------------+ +-------------------------+
某些价值(通常是资产价格)的波动性是 金融衍生品的估值模型。在这种情况下,我们尝试在 运用市场隐含的股票和利率的波动性 价格。
这两个类基本上都有相同的接口如果我们依靠鸭子打字 意外地传递一个RateVolatilitySurface值一个股票期权,否 将引发异常,因为在技术上输入将满足 通过duck类型表示的约束。但是,结果是错误的 我们会得到一个典型的sh t-in,sht-out程序的例子。
显而易见的解决方案是在代码中添加大量 isinstance支票然而,这会很快导致您的业务代码 以样板检查和错误处理为主。为了避免这种情况,我试着 模块中最有用和最简单的模式:
- 为函数参数和返回值分配约束
- 创建一个对其属性进行严格类型检查的类 已填充__slots__变量。
2014年,杰夫金塔拉索夫(jevgeni@tarasov.ch)