2

我有一个带有三个注册函数的方法调度装饰器。一个发送到int,效果很好。在自定义类型上调度的第二个也可以正常工作。第三种也是自定义类型,只不过Class是用lru_cache装饰器包裹的。

(为了让事情更复杂一点,这个类是通过另一个类的方法上的 methoddispatch 以一种迂回的方式实例化的__call__。)

@lru_cache(maxsize=None, typed=True)
class QualifiedInterval:
    # stuff that works

在 Pitch 类中:

@oph_utils.method_dispatch
def augmented(self, other):
    raise NotImplementedError

@augmented.register(int)
def _(self, other):
    return "works fine"


@augmented.register(Interval)
def _(self, other):
    return "works fine too"

@augmented.register(QualifiedInterval)
def _(self, other):
    return "only works if QualifiedInterval class does NOT have lru_cache"

(还有很多事情要做,但这是不起作用的部分。)

基本上 - 如果我有 lru_cache,并将 QualifiedInterval 传递给函数,它不会调度并引发 NotImplementedError。如果我注释掉缓存装饰器,它就可以工作。REPL 的手动类型检查显示相同的类型(“QualifiedInterval”)。我尝试以几种不同的方式调用创建 QualifiedInterval 的命令,并尝试将其分配给变量。还是不行。我尝试在增强函数中进行显式类型检查。如果启用了缓存,类型检查也会失败。

4

1 回答 1

1

分析出了什么问题

基本上 - 如果我有 lru_cache,并将 QualifiedInterval 传递给函数,它不会调度

lru_cache是返回包装任何可调用(包括类)的装饰器的函数。因此,当您将lru_cache应用于QualifiedInterval类时,该变量将分配给包装函数而不是类本身。

>>> @lru_cache(maxsize=None, typed=True)
class QualifiedInterval:
    pass

>>> type(QualifiedInterval)
<class 'functools._lru_cache_wrapper'>

单一调度通过将第一个参数的类型与适当的方法相匹配来工作。但是,当您传入QualifiedInterval的实例时,它的类型与functools._lru_cache_wrapper不匹配,因此单个调度会退回到基本方法(引发NotImplemented

解决方案

教单个调度匹配实际的原始类(类型)而不是包装的类:

@augmented.register(QualifiedInterval.__wrapped__)
def _(self, other):
    return "show now work QualifiedInterval class has an lru_cache"

请注意添加了.__wrapped__通过包装函数到达原始未包装类的属性。

希望这一切都清楚并指明了前进的方向:-)

于 2017-06-17T07:40:50.620 回答