没有项目描述
instruct的Python项目详细描述
一个紧凑、快速的对象系统,可以作为DAO模型的基础。
为此,指令使用__slots__来防止新的属性添加、用于控制类型、事件侦听器和历史更改的属性,以及用于保持纯python实现尽可能快和轻的jinja2驱动的代码生成。
尝试为多个主机服务:
- Support multiple inheritance, chained fields and ^{tt1}$ [Done]
- Support type coercions (via ^{tt3}$) [Done]
- Strictly-typed ability to define fixed data objects [Done]
- Ability to drop all of the above type checks [Done]
- Track changes made to the object as well as reset [Done]
- Fast ^{tt4}$ [Done]
- Native support of pickle [Done]/json [Partial]
- Support List[type] declarations and initializations
- ^{tt5}$-Base class that operates on an ^{tt6}$ cffi struct.
- Cython compatibility
设计目标
这源于我做多个对象系统来表示数据库关系和业务规则的经验。有一件事已经被证明是一个问题,那就是要求尽可能少地使用内存,尽可能少地使用cpu,同时还要防止开发人员试图在整数所属的位置粘贴字符串。
使这个模型更加复杂的是,人们希望在数据进入时“纠正”它。如果执行正确,则可以馈送instruct.Base-派生的类字段,这些字段不是正确的数据类型,但可以通过函数强制(转换)为正确的类型。通过一些工作,可以将lambda val: ...表达式直接内联到setter函数代码中。
最后,多重继承是必须的。迟早,您会为对象之间共享的公共行为创建一个单一的源实现。能够在相关实现之间共享业务逻辑是一件美妙的事情。
这样定义一个继承人不是很好吗:
classMember(Base):__slots__={'first_name':str,'last_name':str,'id':str,}def__init__(self,**kwargs):self.first_name=self.last_name=''self.id=-1super().__init__(**kwargs)classOrganization(Base,history=True):__slots__={'name':str,'id':int,'members':List[Member],'created_date':datetime.datetime,}__coerce__={'created_date':(str,lambdaobj:datetime.datetime.strptime('%Y-%m-%d',obj))}def__init__(self,**kwargs):self.name=''self.id=-1self.members=[]self.created_date=datetime.datetime.utcnow()super().__init__(**kwargs)
它能像这样工作吗?
data={"name":"An Org","id":123,"members":[{"id":551,"first_name":"Jinja","last_name":"Ninja",}]}org=Organization(**data)assertorg.members[0].first_name=='Jinja'org.name="New Name"org.history()
设计
解决多重继承和__slots__问题
考虑下图:
Base1 Base2 \ / Class A
如果两者都定义了__slots__ = (),则类A将能够声明__slots__来保存变量。现在,为了简单起见,我们将考虑两个基址都有__slots__ = ()。
但是,请考虑以下情况:
Base1 Base2 \ / Class A Class B \ / Class C
现在,如果类a具有非空的__slots__,则这是不可能的。
但如果我们能改变规则呢?如果,不知何故,当您__new__创建一个类时,它确实为您提供了一个具有非空__slots__的类的特殊形式,该怎么办?
这样的图表可能如下:
Base1 Base2 \ / Class A Class B | \ / | Class _A Class C Class _B | Class _C
现在,任何有效的多重继承链都可以继续,只要它遵守上述约束——要么是支持类,要么是数据类(在它们的类名前面用下划线表示)。支持类可以从继承,数据类不能。
解决慢度问题
我注意到,编写setter/getter和其他相关函数有固定的模式。使用jinja2,我们可以依赖于不卫生的宏,同时保持一些可接近的外观。比起ast synthesis/traversal,经验不足的开发人员更有可能处理jinja-fied python的块。
调用图性能
基准
在添加强制、事件侦听器、多重继承之前
$ python -m instruct benchmark Overhead of allocation, one field, safeties on: 6.52us Overhead of allocation, one field, safeties off: 6.13us Overhead of setting a field: Test with safeties: 0.40 us Test without safeties: 0.22 us Overhead of clearing/setting Test with safeties: 1.34 us Test without safeties: 1.25 us
再加上这些。安全是昂贵的。
$ python -m instruct benchmark Overhead of allocation, one field, safeties on: 19.25us Overhead of allocation, one field, safeties off: 18.98us Overhead of setting a field: Test with safeties: 0.36 us Test without safeties: 0.22 us Overhead of clearing/setting Test with safeties: 1.29 us Test without safeties: 1.14 us