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

2024-04-17

我想做:

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

Note:我提交了 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 源代码 https://hg.python.org/cpython/file/v3.5.2/Python/ceval.c#l1545, where PyUnicode是Pythonstr type).

这是不幸的,因为对于所有其他类型你可以防止LHS.__mod__通过使用右侧操作数的子类来调用的方法;来自文档 https://docs.python.org/3/reference/datamodel.html#object.__ror__:

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

这本来是这里唯一的选择,str % other一去不复返NotImplemented, all接受 RHS 类型(实际str.__mod__ method https://hg.python.org/cpython/file/v3.5.2/Objects/unicodeobject.c#l13670只接受strRHS 的对象,但在本例中未调用)。

我认为这是 Python 中的一个错误,归档为问题#28598 http://bugs.python.org/issue28598.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以使用 __rmod__ 覆盖 str 的 % 行为? 的相关文章

随机推荐