在 Python 中,class 定义之外的方法与使用 staticmethod 的方法之间有什么区别?

In Python, is what are the differences between a method outside a class definition, or a method in it using staticmethod?

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

但问题的本质与此无异。假设我开发了一个名为 'Matrix' 的 class,它具有实现矩阵的机制。实例化大概会采用列表列表,这将是矩阵条目。

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

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)

我不清楚什么时候一个比另一个好。独立函数并不是 class 定义的真正组成部分,但谁在乎呢?它完成了工作,并且因为 Python 允许来自外部的 "reaching into an object" 引用,所以它似乎可以做任何事情。在实践中,它们(class 和方法)将在同一个模块中结束,因此它们至少在那里链接。

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

z = multiply(a,b)

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

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

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

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

两种方法是:

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

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

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

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

    multiply(x,y)
因此,

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

我错误地混淆了两件事,这让我想到了附加到每个对象实例的方法:

  1. 需要在应该是的文件中普遍可用的函数 暴露在外面;和
  2. 仅在文件内部需要的函数。

multiply() 是类型 1 的示例。任何矩阵 'library' 都应该可以定义矩阵乘法。

我担心的是需要公开所有 'internal' 函数。例如,假设我们想要使外部可用的矩阵 add()、multiple() 和 invert()。但是,假设我们不想在外部提供 - 但在内部需要 - determinant()。

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

来获取代码。

归根结底,这很大程度上取决于惯例。公开一个矩阵乘法函数更有意义,它采用两个矩阵,并且被称为 multiply(x,y)。至于行列式函数,而不是 class 中的 'wrapping it',将其定义为 __determinant(x) 在与 class 定义相同的级别上更有意义矩阵。

您似乎永远无法通过声明真正保护内部方法。您能做的最好的事情就是警告用户。 “dunder”方法给出警告 'this is not expected to be called outside the code in this file'.