【问题标题】:How bad is it to override a method from a third-party module?覆盖第三方模块的方法有多糟糕?
【发布时间】:2011-01-13 03:21:36
【问题描述】:

在 Python 中从另一个第三方模块重新定义类方法有多糟糕?

其实用户可以创建包含numbers with uncertainty的NumPy矩阵;理想情况下,我希望他们的代码不加修改地运行(与代码操作浮点矩阵时相比);特别是,如果矩阵的逆矩阵m 仍然可以用m.I 获得,那将是很好的,尽管m.I 必须用我自己的代码计算(原来的I 方法不起作用,一般)。

重新定义 numpy.matrix.I 有多糟糕?一方面,它确实篡改了我不喜欢的第三方代码,因为它可能不健壮(如果其他模块也这样做呢?...)。另一个问题是新的 numpy.matrix.I 是一个包装器,当原始的 numpy.matrix.I 可以实际应用以获得逆矩阵时,它会产生很小的开销。

对 NumPy 矩阵进行子类化并仅更改其 I 方法是否更好?这将迫使用户更新他们的代码并使用m = matrix_with_uncert(…) 创建不确定的数字矩阵(而不是继续使用numpy.matrix(…),作为浮点矩阵),但也许这是一个不便,应该接受鲁棒性?矩阵求逆仍然可以使用m.I 执行,这很好……另一方面,如果用户可以直接使用numpy.matrix() 构建他们所有的矩阵(浮点数或具有不确定性的数字),那就太好了,而不必费心检查数据类型。

欢迎提出任何意见或其他方法!

【问题讨论】:

    标签: python numpy overriding


    【解决方案1】:

    子类化(它确实涉及覆盖,因为该术语通常被使用)通常比“猴子补丁”(将更改的方法填充到现有的类或模块中)更可取,即使后者可用(内置类型,意思是那些用 C 实现的,可以保护自己免受猴子补丁的影响,而且大多数都这样做)。

    例如,如果您的功能依赖于猴子补丁,那么如果您正在猴子补丁的类在任何时候升级为在 C 中实现(为了速度或专门防御猴子补丁),它将中断并停止升级.第三方包的维护者讨厌猴子补丁,因为这意味着他们从不幸的用户那里得到虚假的错误报告,这些用户(他们不知道)实际上正在使用一个破坏第三方包的有问题的猴子补丁,而后者(除非破坏了猴子-明智的)是完美的。您已经对可能的性能影响发表了评论。

    从概念上讲,“具有不确定性的数字矩阵”与“数字矩阵”是不同的概念。子类化清楚地表达了这一点,猴子补丁试图隐藏它。这确实是猴子修补一般问题的根源:一个通过全球、隐藏的方式运作的隐蔽渠道,没有清晰和透明。从某种意义上说,所有许多实际问题都源于这个根本的概念问题。

    我强烈敦促您拒绝猴子修补,转而采用子类化等干净的解决方案。

    【讨论】:

    • 感谢您对猴子补丁及其潜在问题的清晰描述!我必须说 NumPy 通过支持它们来鼓励定义“某些东西的数组”(numpy.array([any_object]))。所以,我想说“任何对象的矩阵”是 NumPy 非常支持的一个概念——自动支持逐元素添加等等。也就是说,我完全同意你的其余回复!跨度>
    【解决方案2】:

    一般来说,重写...的方法是完全可以接受的

    • 有意允许覆盖
    • 以他们记录的方式(满足 LSP 不会有什么坏处)

    如果两个条件都满足,那么覆盖应该是安全的。

    【讨论】:

      【解决方案3】:

      取决于您对“重新定义”的含义。显然你可以使用你自己的版本,完全没有问题。如果它是一种方法,您也可以通过子类化来重新定义它。

      您还可以创建一个新方法,并将其修补到类中,这种做法称为monkey_patching。像这样:

      from amodule import aclass
      
      def newfunction(self, param):
          do_something()
      
      aclass.oldfunction = newfunction
      

      这将使类的所有实例都使用您的新函数而不是旧函数,包括任何“第四方”模块中的实例。这很有效并且非常有用,但它被认为是非常丑陋和不得已的选择。这是因为 aclass 代码中没有任何内容表明您已经覆盖了该方法,因此很难调试。更糟糕的是,当两个模块对同一件事进行猴子补丁时,情况会变得更糟。那么你真的会感到困惑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-06
        • 2015-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-04
        • 2017-05-10
        • 1970-01-01
        相关资源
        最近更新 更多