轻量级条件解析与求值表达式的构建
pycond的Python项目详细描述
作者:GK 版本:190523
pycond:轻量级声明性条件表达式
目录
什么
你有很多数据,可能是流媒体…
id,first_name,last_name,email,gender,ip_address 1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120 2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2 (...)
你需要过滤。现在,假设我们已经将它们作为dict列表。
您可以强制执行此操作:
foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
或者让这个模块从如下声明中组装一个条件函数:
frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
然后根据不同的状态/事实/模型(…):
foo_users = [ u for u in users if is_foo(state=u) ]
性能与手工制作的python大致相同(系数2-3)。
< Buff行情>在现实生活中,由于
当开发人员决定对数据应用过滤器时,他肯定会
直接使用python优秀的表达能力,如上图所示
通过列表理解。 这是此模块的主要用例。 但为什么还要用另一种工具来做这样的标准工作呢? 有一系列很棒的工具和框架,其中条件解析只是其中的一小部分,例如,pyke或durable以及django世界中的许多人或来自sql语句分析器。 pycond允许自定义 并作为零依赖单模块发布。 所有评估都是通过部分来完成的,而不是lambdas,也就是说,可以非常简单地通过断点、自定义日志记录运算符或查找包装器对操作进行内省和调试。 pycond根据 输出: 在分析之后,生成器将通过组合运算符组合一组嵌套的运算符函数。
这些函数是部分函数,即尚未计算,但有关必需键的信息已存在
可用: 其他进程可以通过可序列化格式(例如json)交付条件结构。
如果您将这些已经标记化的构造交给pycond,那么将绕过标记化器: 生成器的结果是一个"pycondition",它可以针对系统的不同状态运行多次。
状态的评估方式可在生成和运行时自定义。 默认设置是从模块中的初始空 ( 在求值时使用state参数: 您可以提供一个路径分隔符,用于跳入嵌套结构,如so: 您可以提供自己的价值获取功能。 输出: 如您在示例中所见,state参数只是一个约定
对于 这在许多情况下避免了不必要的计算: 当求值分支包含"and"或"and"和"not"组合符时,则
在运行时,我们计算第一个表达式-如果它已经是
错误的。这样就省去了昂贵的深入分支评估,或者
查找是惰性的,甚至不会获取值: 输出: 条件函数是从结构化表达式内部创建的-
但这些是难以键入的
包含许多撇号。 基于文本的条件语法适用于最终用户
直接在文本框中键入。 将原子条件与布尔运算符和嵌套括号结合起来,如: 因此,这样的表达式是有效且正确的: 所有布尔型标准库运算符
默认情况下可用: 默认情况下,pycond使用文本样式运算符。 运算符命名空间应在进程开始时分配,它们是全局的。 否定条件运算符的结果: 在调用运算符之前反转参数 您可以通过自定义函数全局包装所有评估时间条件操作: 您可以通过重复应用 这是通过如下所示的 使用 您可以将单个条件与 组合功能存储在 不要对组合运算符的名称使用空格。用户可以使用它们,但它们在标记化时间之前会被替换,例如 组合条件可以使用括号"["和"]"任意嵌套。 通过 在这个平面列表格式中,括号作为字符串,例如 标记器的工作是分离生成器的表达式字符串。 分隔表达式的不同部分。默认为""。 sep可以是任何单个字符,包括二进制字符。 括号字符不需要分隔,标记器将执行以下操作: 条件函数本身的计算结果并不相等
已经组装了两次。 通过将字符串放入撇号中,您可以将记号赋予器告诉n不必进一步检查,例如分离器: 告诉标记器不要解释下一个字符: 表达式字符串值通过public 通过将 如果不想提供自定义查找函数(可以在其中执行所需的操作)
但要查找自动转换的键,请使用: 通常情况下,条件是在用户空间中,应用于
仅在开发时由开发人员控制。 最终用户可能只从API中提供的许多键中选择一些键。 pycond的 输出: 但是我们可以做得更好-我们仍然计算键的值
只在延迟评估的条件的死胡同中需要。 让我们避免计算这些值,记住
自定义查找功能功能。 pycond确实很容易为您生成这样的自定义查找函数,
如果将getter命名空间传递为 输出: 输出显示,我们甚至没有为条件的死分支调用值提供程序函数。 由pytest2md自动生成,运行pytest2md
pycond的延迟评估功能
为什么
但是如果过滤条件是基于程序之外的决策
控制?也就是说,来自最终用户,通过网络以某种序列化的形式点击程序,这很少是可直接计算的python。备选方案
1.
我只需要一个非常苗条的工具来解析函数,但是这个工具非常透明而且可以定制2.
语法的简单性:易于直接键入,非
程序员也可以从结构化数据(例如从web框架)中进行综合。3.
性能:足以在流过滤器中使用"pyconditions"。
在当前的特性集中,我们有时会差2-3个因子,但(由于延迟评估)通常更好,
与手工制作的列表理解相比。力学
解析
tokenizer
函数中提供给解析器的一组约束来解析条件表达式。
标记器的结果将提供给生成器。importpycondaspccond='[a eq b and [c lt 42 or foo eq bar]]'cond=pc.to_struct(pc.tokenize(cond,sep=' ',brkts='[]'))print(cond)returncond
[['a', 'eq', 'b', 'and', ['c', 'lt', '42', 'or', 'foo', 'eq', 'bar']]]
建筑
f,meta=pc.parse_cond('foo eq bar')assertmeta['keys']==['foo']
结构条件
cond=[['a','eq','b'],'or',['c','in',['foo','bar']]]assertpc.pycond(cond)(state={'a':'b'})==True
评估
默认查找
状态
dict获取表达式中的查找键。
f=pc.pycond('foo eq bar')assertf()==Falsepc.State['foo']='bar'assertf()==True
pycond
是不需要元信息时parse-cond
的快捷方式)。通过自定义状态
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
0
深入查找/嵌套状态
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
1
自定义查找和值传递
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
2
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
3
< Buff行情>pyconds'
[标题:默认查找函数,fmatch=pycond.py,lmatch:def state\u get
功能。延迟评估
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
4
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
5
建筑条件来自文本
语法
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
6
原子条件
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
7
查找键
时,则将co
设置为truthy
函数:id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
8
id,first_name,last_name,email,gender,ip_address
1,Rufe,Morstatt,rmorstatt0@newsvine.de,Male,216.70.69.120
2,Kaela,Scott,scott@opera.com,Female,73.248.145.44,2
(...)
9
not lookup_键
时,则co
设置为错误
功能:foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
0
条件运算符
foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
1
<详情>nr运算符 别名 添加
和
均衡器
地板
ge >;= gt >; iadd += 着陆
ifloordiv /= ilshift <;= imod %= imul *=
首次公开发行股票
ior = irshift >;= 是
不是
isub -= itruediv /= ixor ^= le <;= lshift <; lt <; 模式 % mul * ne != < < > > >
功率
或 rshift >; sub - truediv / xor ^ 项目获取器
长度提示
<表><详细内容><详情> concat + 包含
计数
索引
方法调用方
<表><详细内容>iconcat += 使用符号运算符
Ops_Use_Symbolic
仅将整个流程切换为符号样式。ops_use_symbolic_and_txt
将processwide切换为允许的两种符号。foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
2
< Buff行情>扩展条件运算符
foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
3
否定
不
foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
4
反转
rev
foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
5
< Buff行情>rev
和not
可以按任何顺序组合。包装条件运算符
全局包装
foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
6
run_all ops_throu
api函数来编写这样的包装器。条件局部包装
Ops_-Thru
参数完成的:foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
7
< Buff行情>ops_thru
是调试意外结果的好方法,因为
可以在那里添加断点或记录器。组合操作
和
而不是
或
是否
xor
默认情况下。pycond.comb-ops
dict中,可以扩展。和not
->;和_not
嵌套
brkts
config参数,您可以在构建时将它们更改为其他分隔符。标记化详细信息
< Buff行情>
['[','a','and''b',']'…]
功能
分隔符
foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
8
< Buff行情>foo_users=[uforuinusersif([u['gender']=='Male'oru['last_name']=='Scott')and'@'inu['email'])]
9
< Buff行情>撇号
frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
0
转义
frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
1
建筑
autoconv:将值转换成python简单类型
pycond.py_type
函数自动转换为bools和numbers。autoconv
参数设置为false
或使用撇号:frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
2
frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
3
按需上下文和延迟评估
ctx_builder
只允许在运行时计算这些键,
用户决定将条件建立在:
在条件构建时,为all函数移交一个命名空间
可用于构建CTX。pycon
将为您返回一个上下文生成器函数,只调用那些函数
条件实际需要的。frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
4
frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
5
lookup_provider
:frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
6
frompycondimportparse_condcond='email contains .de and gender eq Male or last_name eq Scott'is_foo=parse_cond(cond)
7
推荐PyPI第三方库