PEAK-Rules的扩展,用于优先级方法以避免AmbiguousMethods情况
项目描述
此模块提供了四个装饰器
prioritized_when
prioritized_around
prioritized_before
prioritized_after
它们的行为类似于其 peak.rules 对应物,但它们接受一个可选的 prio 参数,可以用来提供一个可比较的对象(通常是整数),该对象将被用于在存在多个规则适用于给定参数且没有规则比另一个更具体的情况下进行去歧义。也就是说,在 peak.rules.AmbiguousMethods 会被抛出的情况下。
这对于希望通过通用函数进行扩展的库非常有用,但希望用户可以轻松覆盖方法而无需弄清楚如何编写更具体的规则或当这不可行时。
例如,TurboJson提供了一个 jsonify 函数,看起来像这样
>>> def jsonify(obj): ... "jsonify an object"
并且扩展了它,使其可以以类似这种方式处理SqlAlchemy映射类
>>> from peak.rules import when >>> def jsonify_sa(obj): ... print "You're a SA object and I'm going to jsonify you!" >>> when(jsonify, "hasattr(obj, 'c')")(jsonify_sa) # doctest: +ELLIPSIS <function jsonify_sa at ...> >>> class Person(object): ... def __init__(self): ... self.c = "im a stub" >>> jsonify(Person()) You're a SA object and I'm going to jsonify you!
到目前为止一切顺利,然而,当库的用户想要覆盖内置实现时,由于他们必须编写更具体的规则,这可能会变得相当困难,例如
hasattr(self, 'c') and isinstance(obj, Person)
注意 hasattr 测试,即使 isinstance(obj, Person) 意味着它,只是为了使其比内置的更具体,随着表达式的复杂化,这会变得更加繁琐。
否则就会发生这种情况
>>> def jsonify_Person(obj): ... print "No way, I'm going to jsonify you!" >>> when(jsonify, (Person,))(jsonify_Person) # doctest: +ELLIPSIS <function jsonify_Person at ...> >>> try: ... jsonify(Person()) ... except AmbiguousMethods: ... print "I told you, gfs can sometimes be a pain" I told you, gfs can sometimes be a pain
为了解决这个问题,可以使用 prioritized_when 来提供一个实现,该实现将覆盖用 when 声明的实现
>>> def jsonify_Person2(obj): ... print "No way, I'm going to jsonify you!" >>> prioritized_when(jsonify, (Person,))(jsonify_Person2) # doctest: +ELLIPSIS <function jsonify_Person2 at ...> >>> jsonify(Person()) No way, I'm going to jsonify you!
注意,我们不需要 prio 参数。这是因为用 prioritized_when 装饰的方法始终覆盖那些用 peak.rules.when 装饰的方法。
用 prioritized_when 装饰的方法也可以使用 prio 参数覆盖由同一装饰器装饰的其他方法,比较较大者胜出,如果两者相等,则将像往常一样引发 AmbiguousMethods。
>>> def jsonify_Person3(obj): ... print "Don't be so smart, I am, my prio is higher!">>> prioritized_when(jsonify, (Person,), prio=1)(jsonify_Person3) # doctest: +ELLIPSIS <function jsonify_Person3 at ...>>>> jsonify(Person()) Don't be so smart, I am, my prio is higher!
为了方便起见,还提供了一个 generic 装饰器,其行为类似于 peak.rules.dispatch.generic,但将要绑定到装饰函数属性上的 when、…、`after` 装饰器将被优先考虑。
>>> @generic ... def f(n): pass >>> f(5) Traceback (most recent call last): ... NoApplicableMethods: ((5,), {})
添加默认规则
>>> @f.when() ... def default_f(n): ... return n >>> f(5) 5
添加一个默认规则以覆盖之前的规则
>>> @f.when(prio=1) ... def new_default_f(n): ... return n+1 >>> f(5) 6
项目详情
下载文件
为您的平台下载文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。