功能分析描述语言基础包
项目描述
func_adl
使用Python中类似于SQL的概念构建层次数据查询。
func_adl
使用类似SQL的语言,并从ROOT文件或ATLAS xAOD文件中提取数据和计算值,并以列格式返回。它目前被用作ServiceX转换器的一部分。
这是一个具有后端无关代码以查询层次数据的基包。很可能会安装以下包之一
- func_adl_xAOD: 用于在ServiceX中运行的ATLAS & CMS实验xAOD文件
- func_adl_uproot: 用于运行平面root文件
- func_adl.xAOD.backend: 用于使用Docker在本地文件上运行
有关每个后端可能的表达式和功能的信息,请参阅文档。
捕获的变量
Python支持在lambda
值和函数中支持闭包。此库将在调用select方法时解析这些闭包。例如(其中ds
是数据集)
met_cut = 40
good_met_expr = ds.Where(lambda e: e.met > met_cut).Select(lambda e: e.met)
met_cut = 50
good_met = good_met_expr.value()
裁剪将在40处应用,因为当调用Where
函数时met_cut
的值是40。这也适用于函数内部捕获的变量。
语法糖
有几个Python表达式和习惯用法在您的背后被转换为func_adl
。请注意,这些必须位于ObjectStream
方法之一的lambda
函数内部,例如Select
、SelectMany
或Where
。
名称 | Python表达式 | func_adl 翻译 |
---|---|---|
列表推导式 | [j.pt() for j in jets] |
jets.Select(lambda j: j.pt()) |
列表推导式 | [j.pt() for j in jets if abs(j.eta()) < 2.4] |
jets.Where(lambda j: abs(j.eta()) < 2.4).Select(lambda j: j.pt()) |
列表推导式 | [j.pt()+e.pt() for j in jets for e in electrons] |
jets.Select(lambda j: electrons.Select(lambda e: j.pt()+e.pt())) |
注意:对于列表推导式有效的一切也适用于生成器表达式。
可扩展性
有两个可扩展点
EventDataset
应该被派生以提供执行器。EventDataset
可以使用 Python 的类型提示系统,允许编辑器和其他智能输入系统对表达式进行类型检查。类型数据越多,系统可以帮助得越多。- 定义一个可以在 LINQ 表达式中调用的函数
- 定义新的流方法
- 可以在函数或方法调用点插入回调,这将允许修改
ObjectStream
或调用点的ast
。
EventDataSet
一个 EventDataSet
的示例
class events(EventDataset):
async def execute_result_async(self, a: ast.AST, title: Optional[str] = None):
await asyncio.sleep(0.01)
return a
以及一些使用它的 func_adl
代码
r = (events()
.SelectMany(lambda e: e.Jets('jets'))
.Select(lambda j: j.eta())
.value())
- 当调用
.value()
方法时,将调用带有表示查询的完整ast
的execute_result_async
。这是将查询发送到后端进行实际处理的地方。 - 通常,
events
的构造函数将接受要处理的数据集名称,然后可以在execute_result_async
中使用。
类型化 EventDataset
上述声明的一个小变化,查询没有变化
class dd_jet:
def pt(self) -> float:
...
def eta(self) -> float:
...
class dd_event:
def Jets(self, bank: str) -> Iterable[dd_jet]:
...
def EventNumber(self, bank='default') -> int
...
class events(EventDataset[dd_event]):
async def execute_result_async(self, a: ast.AST, title: Optional[str] = None):
await asyncio.sleep(0.01)
return a
这不是必需的,但当这样做时
- 使用类型提供选项/猜测的编辑器现在会亮起来,只要它们有合理的类型检查功能。
- 如果遗漏了必需的参数,将生成错误
- 如果遗漏了默认参数,它将自动填充。
应该注意的是,类型和表达式跟随者并不十分复杂!虽然它可以跟随方法调用,但不会跟随其他很多内容!
代码应在 Python 3.11 或使用 from __future__ import annotations
时正常工作。
基于类型的回调
通过在类型系统中添加一个函数和一个引用,可以在遍历 func_adl
时执行任意代码。保持查询和 events
定义相同,我们可以使用类定义的装饰器直接将信息添加到 Python 类型声明中
from func_adl import ObjectStream
from typing import TypeVar
# Generic type is required in order to preserve type checkers ability to see
# changes in the type
T = TypeVar('T')
def add_md_for_type(s: ObjectStream[T], a: ast.Call) -> Tuple[ObjectStream[T], ast.AST]:
return s.MetaData({'hi': 'there'}), a
@func_adl_callback(add_md_for_type)
class dd_event:
def Jets(self, bank: str) -> Iterable[dd_jet]:
...
- 当处理
.Jets()
方法时,会调用add_md_for_type
,带有当前对象流和 ast。 - 这里的
add_md_for_type
添加元数据并返回更新后的流和 ast。 - 没有阻止函数解析 AST、删除或添加参数、添加更复杂的元数据或根据调用点的参数执行任何这些操作的限制。
参数化方法调用
这是一种非常特殊形式的回调,它是为了支持像 C++ 中模板的互操作这样的功能而实现的。它允许你写像这样的事情
result = (ds
.SelectMany(lambda e: e.Jets())
.Select(lambda j: j.getAttribute[float]('moment0'))
.AsAwkward('moment0')
)
注意在 getAttribute
调用中的 [float]
。这只会在 Jet
类中的属性 getAttribute
被标记为装饰器 func_adl_parameterized_call
时发生
T = TypeVar('T')
def my_callback(s: ObjectStream[T], a: ast.Call, param_1) -> Tuple[ObjectStream[T], ast.AST, Type]:
...
class Jet:
@func_adl_parameterized_call()
@property
def getAttribute(self):
...
在这里,param_1
将以 float
类型调用。请注意,这意味着在调用此函数时,参数值必须解析为实际值——它们不会转换为 C++。在这种情况下,my_callback
可以注入 MetaData
来构建对 getAttribute
的模板调用。my_callback
返回的元组与上面的 add_md_for_type
相同——只是第三个参数必须返回调用的返回类型。
如果使用了多个参数(如 j.getAttribute['float','int'])['moment0']
),则 param_1
是一个包含两个元素的元组。
函数定义
拥有可以在后端直接调用的函数是有用的——或者使用函数调用来人为地将某些内容插入到 func_adl
查询流中(如 MetaData
)。例如,C++ 后端使用此方法插入内联 C++ 代码。使用 func_adl_callable
装饰器来完成此操作。
def MySqrtProcessor(s: ObjectStream[T], a: ast.Call) -> Tuple[ObjectStream[T], ast.Call]:
'Can add items to the object stream'
new_s = s.MetaData({'j': 'func_stuff'})
return new_s, a
# Declare the typing and name of the function to func_adl
@func_adl_callable(MySqrtProcessor)
def MySqrt(x: float) -> float:
...
r = (events()
.SelectMany(lambda e: e.Jets('jets'))
.Select(lambda j: MySqrt(j.eta()))
.value())
在上面的示例中,对 MySqrt
的调用将被传递回后端。然而,在调用之前将插入 MetaData
。可以使用 C++ 定义 MySqrt
函数(或类似函数)。
请注意,如果 MySqrt
总是在后端定义,且不需要额外的数据,则可以在装饰器调用中省略 MySqrtProcessor
。
添加新的 Collection API
像 First
这样的函数不应存在于 ObjectStream
中,因为那是定义的最高级别集合。然而,在事件上下文中,它们非常有意义。后面的代码需要一种方式来跟踪这些(类型提示系统不需要修改,只需在您的 Event
对象中适当地声明您的集合)。
例如,请参阅 test_type_based_replacement
文件。类级别装饰器称为 register_func_adl_os_collection
。
开发
在构建新版本并通过测试后,您可以通过在 github
上创建新版本来发布它。创建发布时运行的动作将将其发送到 pypi
。
项目详情
下载文件
下载适用于您平台文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分布
构建分发版
func_adl-3.3.3.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 62e2928b9ceb911bc889532403d6e786a0561f0d51b7a8c9335ee499b0a61d20 |
|
MD5 | 514d0584f7770252b987bfbf1e7a8a0e |
|
BLAKE2b-256 | 71ceb936cd826b04fd223560118ee315e6159233fc497a484e6dca8eca6f88e2 |
func_adl-3.3.3-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 5322f68cc5de1a9b7c825b6c22329fc2a2cd1e3ae51797f2849d3a71bc1ce7d6 |
|
MD5 | ca1e063de0917bb520ab5ba51d27c2d5 |
|
BLAKE2b-256 | cb103abd3a830dd1abaeb9eba7cc76692ac430ad3ac5800a11139cccb8c715b5 |