是否可以使用__rmod__覆盖str的%行为?

时间:2016-11-03 13:04:18

标签: python string operator-overloading

我想这样做:

x %doSomething% y

对于任何x和任何y都很容易做到(见下面的代码),除非x是str。

是否有任何方法(例如添加特殊方法或引发特定错误)导致旧样式字符串格式化失败(类似于1%doSomthing如何因TypeError而失败)并恢复为doSomething对象中定义的__rmod__方法?

class BinaryMessage(object):
  def __init__(self, fn):
    self._fn = fn
  def __rmod__(self, LHS):
    return BinaryMessagePartial(self._fn, LHS)

class BinaryMessagePartial(object):
  def __init__(self, fn, LHS):
    self._fn = fn
    self._LHS = LHS
  def __mod__(self, RHS):
    return self._fn(self._LHS, RHS)

def _doSomething(a , b):
  return a + b

doSomething = BinaryMessage(_doSomething)

result = 5 %doSomething% 6
assert result == 11

2 个答案:

答案 0 :(得分:7)

注意:我为Python 2.7和3.5及更高版本提交了补丁。这些已经登陆并且是2.7.14,3.5.4,3.6.1和3.7的一部分,其中OP示例现在按预期工作。对于旧版本,请参阅下文。

不幸的是,这在Python中目前是不可能的。行为在评估循环中硬编码:

TARGET(BINARY_MODULO) {
    PyObject *divisor = POP();
    PyObject *dividend = TOP();
    PyObject *res = PyUnicode_CheckExact(dividend) ?
        PyUnicode_Format(dividend, divisor) :
        PyNumber_Remainder(dividend, divisor);

(来自Python 3.5 source code,其中PyUnicode是Python str类型。)

这很不幸,因为对于所有其他类型,您可以通过使用右侧操作数的子类来阻止调用LHS.__mod__方法;来自documentation

  

注意:如果右操作数的类型是左操作数类型的子类,并且该子类提供了操作的反射方法,则此方法将在左操作数的非反射方法之前调用。此行为允许子类覆盖其祖先的操作。

这是唯一的选项,str % other永不返回NotImplemented所有 RHS类型都被接受(实际的str.__mod__ method只接受{{1} RHS的对象,但在这种情况下不调用。)

我认为这是Python中的一个错误,以issue #28598提交。

答案 1 :(得分:0)

最终,我选择了>>并写了一个装饰器来做到这一点-参见https://pypi.org/project/coppertop/