【问题标题】:Defining "overloaded" functions in python在 python 中定义“重载”函数
【发布时间】:2012-07-09 07:41:34
【问题描述】:

我真的很喜欢“魔法方法”的语法或任何它们在 Python 中的调用方式,比如

class foo:
    def __add__(self,other): #It can be called like c = a + b
        pass

电话

c = a + b

然后被翻译成

a.__add__(b)

是否可以为“非魔法”功能模仿这种行为?在数值计算中,我需要 Kronecker 产品,并且渴望拥有这样的“kron”函数

kron(a,b) 

事实上

a.kron(b)?

用例是:我有两个相似的类,比如矩阵和向量,它们都有克罗内克积。我想打电话给他们

a = matrix()
b = matrix()
c = kron(a,b)

a = vector()
b = vector()
c = kron(a,b)

矩阵和向量类定义在一个 .py 文件中,因此共享公共命名空间。那么,实现上述功能的最佳(Pythonic?)方法是什么?可能的解决方案:

1) 拥有一个 kron() 函数并进行类型检查

2) 有不同的命名空间

3) ?

【问题讨论】:

    标签: python magic-methods multiple-dispatch


    【解决方案1】:

    python 默认操作符方法(__add__ 等)是硬连线的; python 会寻找它们,因为操作符实现会寻找它们。

    然而,没有什么能阻止你定义一个做同样事情的kron 函数;在传递给它的对象上查找__kron__ 或__rkron__:

    def kron(a, b):
        if hasattr(a, '__kron__'):
            return a.__kron__(b)
        if hasattr(b, '__rkron__'):
            return b.__rkron__(a)
        # Default kron implementation here
        return complex_operation_on_a_and_b(a, b)
    

    【讨论】:

    • 谢谢,这正是我要找的。​​span>
    • 对于一个完整的解决方案,您可能想要实现完整的规则链 - 即 kr = a.__kron__(b); if kr is not NotImplemented: return kr(对于 b.__rkron__ 也是如此 - 如果它是 @ 的子类,则首先给 b 987654329@。但是,如果您不希望客户使用自己对特定领域的奇怪定义来创建自己的类,那这可能有点过头了。
    【解决方案2】:

    您所描述的是multiple dispatch 或多方法。魔术方法是实现它们的一种方式,但实际上更常见的是拥有一个可以注册特定类型实现的对象。

    例如http://pypi.python.org/pypi/multimethod/会让你写

    @multimethod(matrix, matrix)
    def kron(lhs, rhs):
        pass
    
    @multimethod(vector, vector)
    def kron(lhs, rhs):
        pass
    

    自己写一个多方法装饰器很容易; BDFL 在an article 中描述了一个典型的实现。这个想法是 multimethod 装饰器将类型签名和方法与注册表中的方法名称相关联,并用生成的方法替换该方法,该方法执行类型查找以找到最佳匹配。

    【讨论】:

      【解决方案3】:

      从技术上讲,实现类似于“标准”运算符(以及类似运算符 - 想想len() 等)的行为并不困难:

      def kron(a, b):
          if hasattr(a, '__kron__'):
              return a.__kron__(b)
          elif hasattr(b, '__kron__'):
              return b.__kron__(a)
          else:
              raise TypeError("your error message here")
      

      现在您只需在相关类型上添加一个__kron__(self, other) 方法(假设您可以控制这些类型,或者它们不使用槽或任何其他会阻止在类语句主体之外添加方法的东西)。

      现在我不会像上面的 sn-p 那样使用 __magic__ 命名方案,因为这应该是为语言本身保留的。

      另一种解决方案是维护type:specifici function 映射并让“通用”kron 函数查找映射,即:

      # kron.py
      from somewhere import Matrix, Vector
      
      def matrix_kron(a, b):
          # code here
      
      def vector_kron(a, b):
          # code here
      
      KRON_IMPLEMENTATIONS = dict(
          Matrix=matrix_kron,
          Vector=vector_kron,
          )
      
      def kron(a, b):
          for typ in (type(a), type(b)):
              implementation = KRON_IMPLEMENTATION.get(typ, None)
              if implementation:
                  return implementation(a, b)
          else:
              raise TypeError("your message here")
      

      此解决方案不适用于继承,但它“不那么令人惊讶” - 不需要猴子补丁,也不需要 __magic__ 名称等。

      【讨论】:

      • 为什么要将它绑定到特定类型?现在排除了子类或兼容的实现。 for type_, imp in KRON_IMPLEMENTATION.iteritems(): if isinstance(a, type_) 至少会包含子类。
      • 此外,__magic__ 双下划线名称本身并不限于 Python 语言功能。我认为,如果作为文档化 API 的一部分用作覆盖行为的钩子,它们会立即被识别出来。例如,zope.interface 使用 __implemented__ and __provides__。因此__kron__ 和__rkron__ 非常适合这种用法。
      • @MartijnPieters :我确实提到第二个解决方案不适用于继承(简单的isinstance 检查可能会中断,具体取决于序列中的类型顺序和可能的菱形继承)。 wrt/__magic__ 名称,文档明确指出这些标识符是保留的 (docs.python.org/reference/…)。 Zope(和其他一些软件包)不尊重这一点,但如果没有很好的理由,这仍然不是一件好事 - IOW:如果你真的不需要它,不要这样做。
      • “可能会在没有警告的情况下损坏”是升级主要 python 版本时必须处理的问题。
      【解决方案4】:

      我认为拥有一个委托实际计算的单个函数是一种很好的方法。如果 Kronecker 产品只适用于两个相似的类,您甚至可以在函数中进行类型检查:

      def kron(a, b):
          if type(a) != type(b):
              raise TypeError('expected two instances of the same class, got %s and %s'%(type(a), type(b)))
          return a._kron_(b)
      

      然后,你只需要在类上定义一个_kron_ 方法。这只是一些基本示例,您可能希望对其进行改进以更优雅地处理类没有_kron_ 方法的情况,或者处理子类。

      标准库中的二进制操作通常具有反向对偶(__add__ 和 __radd__),但由于您的运算符仅适用于相同类型的对象,因此在这里没有用处。

      【讨论】:

      • type(a) != type(b) 是一个非常糟糕的主意——它不会处理子类,更不用说鸭子类型了,并且检查将通过,例如,kron('a', 'b'),即使这没有意义。如果你真的想要进行类型检查,你会想要:if not isinstance(a, matrix) or not isinstance(b, matrix):。但最好只检查魔术方法。
      • 我知道,我在回答中说过。我们的情况是 kron 只为相同类型的对象定义,因此类型检查(在任何其他情况下都会很难看,我同意)。
      猜你喜欢
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2021-07-20
      • 1970-01-01
      相关资源
      最近更新 更多