Python中的intensional集合
项目描述
Intensional(规则定义)集合用于Python。
概述
定义集合有两种方式:内涵和外延。外延集合如 set([1,3,5,'daisy']) 明确地列举了集合的每个成员。
与此相反,内涵集合是通过规则定义的。例如“所有质数的集合”或“以'a'开头并以't'结尾的每个单词。内涵集合通常是无限的。可能可以生成其成员的列表,但并不像“给我所有东西!”这样的 for 循环那么简单。
一旦你知道你在寻找什么,内涵集合就无处不在。Python不直接表示它们,但正则表达式、许多列表推导式以及所有类型的测试和过滤操作都是内涵集合概念的体现。许多函数测试某个事物是否“合格”。例如,os.path.isdir(d) 检查 d 是否属于合法目录的集合,而 isinstance(s, str) 检查 s 是否属于 str 对象的集合。甚至核心的 if 条件语句也可以解释为测试是否属于内涵集合——通过测试的所有项的集合。
许多此类测试具有时间性——它们确定一个值是否是当前成员。如果条件改变,答案可能会在未来发生变化。其他测试随时间保持不变。%%734 将永远不是一个有效的 Python 标识符,无论测试多少次——除非整个 Python 宇宙的规则发生变化。
内涵集合是所有编程的一部分,即使它们没有被明确地表示或以此名称命名。``intensional`` 帮助 Python 程序直接表示内涵集合。
用法
intensional 定义了几个集合 IntensionalSet 子类,如 Any、Every、ButNot 和 EitherOr。这些大致对应于集合操作并集、交集、差集和对称差集(也称为 xor)。在这些中,Any 是最有用的。
from intensional import * name = 'Stephen' if name in Any('Steve', 'Steven', 'Stephen'): print 'Good name!'
到目前为止,这里没有什么是您不能用标准的 Python set 数据类型完成的。因此,让我们扩展到更通用的内涵集合。
if name in Test("x.startswith('S')"): print "Your name starts with S!"
Test 在其构造函数中接受一个 lambda 表达式或字符串。如果是一个字符串,Test 假设有趣的变量名是 x,并使用自动提供的 lambda x: 前缀编译字符串表达式。这使得代码更加简洁和清晰。现在集合开始变得更有趣。
starts_with_S = Test("x.startswith('S')") ends_with_n = Test("x.endswith('n')") if name in Every(starts_with_S, ends_with_n): ... # Stephen and Steven pass, but Steve does not
当然,这也可以表示为
if name in Test("x.startswith('S') and x.endswith('n')"): ... # Stephen and Steven pass, but Steve does not
或者甚至是
S_something_n = starts_with_S & ends_with_n if name in S_something_n: ...
字符串搜索
intensional 定义了正则表达式 (Re) 和 glob (Glob) 字符串匹配的集合。例如
name = 'Stephen' if name in Re(r'\b(s\w*)\b', Re.I): print 'Good name, {}'.format(Re._[1])
请注意,这启用了一种(或与标准的 re 模块相比的替代方法)的 en passant 赋值形式,这至少缩短了正则表达式条件语句一行。一个改进版的 re.MatchObject 在 Re._ 中可用。此对象可以索引以获取正则表达式匹配组。对于命名组(例如 (?P<firstname>\w+)),可以通过属性检索匹配的值:Re._.firstname。可以通过这种方式访问所有其他 re.MatchObject 方法和属性,例如 Re._.start(1) 和 Re._.span(1)。
对于简单匹配,遵循 Unix glob 表达式规则的 Glob 类可能更简单
- if name in Glob('S*')
…
类型成员资格
if x in Instances(int): ...
与
if isinstance(x, int): ...
存在一个别名 IsInstance 用于 Instances,在单数结构在语言上更自然的情况下使用。还有一个别名 Type 也是可用的。
集合操作
intensional 支持一些,但不是所有的 Python 经典 set 操作。有两个主要规则
IntensionalSet 尝试支持所有 collections.Set 方法,如 union() 和 intersection()。但 IntensionalSet 对象是不可变的,因此不支持由 collections.MutableSet 定义的自我修改操作,如 add()、pop() 和 |=。
由于它们是由规则定义的,而不是显式的成员列表,因此通常无法确定 IntensionalSet 的基数(即 len()),也不能迭代所有成员或测试相等性。主要使用 IntensionalSet 对象来确定成员资格。
由于实现细节,IntensionalSet类与collections.Set平行,但不是真正的子类。
扩展
定义新的IntensionalSet子类,以更通用的方式定义其他类型的逻辑测试,语言上更“干净”,使得代码更易于阅读。例如,Instances内省集定义如下
class Instances(with_metaclass(MementoMetaclass, IntensionalSet)): """ An object is in an IsInstance if it is an instance of the given types. """ def __init__(self, *args): self.types = tuple(args) def __contains__(self, item): return isinstance(item, self.types)
__init__()仅记录创建集合时使用的参数,而__contains__()则执行测试,回答:给定项是否属于使用这些参数创建的集合?
这里的唯一复杂性在于with_metaclass(MementoMetaclass, IntensionalSet)短语,它仅仅是一个兼容性机制,以便能够在Python 2或Python 3中定义具有给定元类的类。
MementoMetaclass被用于一旦创建,集合对象就从缓存中获取,而不是在后续提及时冗余重建。这是一个有用的性能优化。例如,对于正则表达式,它允许Re.__init__()集合构造函数仅编译一次正则表达式,即使程序中包含许多对Re(<some regular exprssion>)的提及。更高的性能是将构建的集合分配给名称/变量,并通过该名称进行引用。这样
integers = Instances(int) if x in integers: ...
所需的工作较少,如果测试要频繁执行,则更受青睐。但这种预命名只是一个优化,并非必需。
if x in Instances(int): ...
和
注意
开始使用pytest和tox进行自动多版本测试。
现在已成功打包,并针对所有最新的Python版本进行了测试:2.6、2.7、3.2和3.3,以及一个(2.5)不是非常近期的版本,以及一个(PyPy 1.9,基于Python 2.7.2)具有不同实现的版本。
intensional是重新思考如何对集合中的项进行测试以及/或选择的一个更大项目的一个方面。敬请期待!
作者Jonathan Eunice或@jeunice on Twitter欢迎您的评论和建议。
安装
要安装最新版本
pip install -U intensional
在特定Python版本下easy_install(以3.3为例)
python3.3 -m easy_install --upgrade intensional
(您可能需要在这些命令前加上“sudo”以授权安装。如果它们已经安装,则可以使用--upgrade
标志;将其添加到包名之前。)
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源分发
intensional-0.222.zip的散列
算法 | 哈希摘要 | |
---|---|---|
SHA256 | d93be13c8b375a66f5a2d6ebc3e7826b41791cfe4d2ce78894dccfcbf32f5300 |
|
MD5 | e90e7a909f0b313b3583b274ae79ed48 |
|
BLAKE2b-256 | 5245f6fd8f32104d039fa960ab706876e727e885ce23984a87da92e80d74bbdc |
intensional-0.222.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 258a9686d247c753bcf8e703dac4acf35a8629bce4640a28ef6c702e17e94a98 |
|
MD5 | 742e65314b26182987291033168720e1 |
|
BLAKE2b-256 | e27418c62ed6f2c69580866a246124a6646f0e2f56c4438f67856333fecff79a |