首页 > 解决方案 > 在 Python 中,类定义之外的方法与使用静态方法的方法之间有什么区别?

问题描述

我一直在进行一组非常密集的计算。这一切都是为了支持我遇到的特定问题。

但问题的性质与此没有什么不同。假设我开发了一个名为“Matrix”的类,它具有实现矩阵的机制。实例化可能会采用列表列表,这将是矩阵条目。

现在我想提供一个乘法方法。我有两个选择。首先,我可以像这样定义一个方法:

class Matrix():
    def __init__(self, entries)
    # do the obvious here
    return

    def determinant(self):
        # again, do the obvious here
        return result_of_calcs

    def multiply(self, b):
        # again do the obvious here
        return

如果我这样做,两个矩阵对象 a 和 b 的调用签名是

a.multiply(b)...

另一种选择是@staticmethod。然后,定义如下:

    @staticethod
    def multiply(a,b):
    # do the obvious thing.

现在调用签名是:

z = multiply(a,b)

我不清楚什么时候一个比另一个好。独立函数并不是真正的类定义的一部分,但谁在乎呢?它完成了工作,并且因为 Python 允许从外部“进入对象”引用,它似乎可以做任何事情。在实践中,它们(类和方法)最终会出现在同一个模块中,因此它们至少在那里链接。

另一方面,我对@staticmethod 方法的理解是该函数现在是类定义的一部分(它定义了其中一个方法),但是该方法没有传入“自我”。在某种程度上这很好,因为调用签名更好看:

z = multiply(a,b)

并且该函数可以访问所有实例的方法和属性。

这是查看它的正确方法吗?是否有充分的理由去做其中之一?它们在哪些方面不等效?

标签: python-3.xstatic-methods

解决方案


自从回答这个问题以来,我已经做了很多 Python 编程。

假设我们有一个名为 matrix.py 的文件,它有一堆用于操作矩阵的代码。我们想提供一个矩阵乘法。

这两种方法是:

  1. 使用签名 multiply(x,y) 定义一个独立的函数
  2. 使其成为所有矩阵的方法:x.multiply(y)

矩阵乘法就是我所说的二元函数。换句话说,它总是需要两个参数。

诱惑是使用#2,以便矩阵对象“随处携带”乘法的能力。然而,与它相乘唯一有意义的是另一个矩阵对象。在这种情况下,有两种同样好的方法可以做到这一点,即:z=x.multiply(y) 或 z=y.multiply(x)

但是,更好的方法是在文件中定义一个函数,即:

    multiply(x,y)

因此,multiply() 是任何使用“库”的代码都期望可用的函数。它不需要与每个矩阵相关联。而且,由于用户将执行“导入”,他们将获得乘法方法。这是更好的代码。

我错误地混淆了两件事,导致我使用附加到每个对象实例的方法:

  1. 需要在文件内部普遍可用的函数应该在文件外部公开;和
  2. 仅在文件内部需要的函数。

multiply() 是类型 1 的示例。任何矩阵“库”都应该可能定义矩阵乘法。

我担心的是需要公开所有“内部”功能。例如,假设我们要使外部可用的矩阵 add()、multiple() 和 invert()。然而,假设我们不想让外部可用——但内部需要——determinant()。

“保护”用户的一种方法是在矩阵的类声明中使行列式成为函数(def 语句)。然后保护它免受暴露。但是,如果他们知道内部结构,没有什么能阻止代码用户通过使用方法 matrix.determinant() 访问。

最后,很大程度上归结为惯例。公开一个接受两个矩阵的矩阵乘法函数更有意义,它被称为乘法(x,y)。至于行列式函数,与其将其“包装”在类中,不如将其定义为与矩阵的类定义相同级别的 __determinant(x) 更有意义。

您似乎永远无法通过声明来真正保护内部方法。您能做的最好的事情就是警告用户。“dunder”方法给出警告“预计不会在此文件中的代码之外调用它”。


推荐阅读