python-3.x - 在 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 编程。
假设我们有一个名为 matrix.py 的文件,它有一堆用于操作矩阵的代码。我们想提供一个矩阵乘法。
这两种方法是:
- 使用签名 multiply(x,y) 定义一个独立的函数
- 使其成为所有矩阵的方法:x.multiply(y)
矩阵乘法就是我所说的二元函数。换句话说,它总是需要两个参数。
诱惑是使用#2,以便矩阵对象“随处携带”乘法的能力。然而,与它相乘唯一有意义的是另一个矩阵对象。在这种情况下,有两种同样好的方法可以做到这一点,即:z=x.multiply(y) 或 z=y.multiply(x)
但是,更好的方法是在文件中定义一个函数,即:
multiply(x,y)
因此,multiply() 是任何使用“库”的代码都期望可用的函数。它不需要与每个矩阵相关联。而且,由于用户将执行“导入”,他们将获得乘法方法。这是更好的代码。
我错误地混淆了两件事,导致我使用附加到每个对象实例的方法:
- 需要在文件内部普遍可用的函数应该在文件外部公开;和
- 仅在文件内部需要的函数。
multiply() 是类型 1 的示例。任何矩阵“库”都应该可能定义矩阵乘法。
我担心的是需要公开所有“内部”功能。例如,假设我们要使外部可用的矩阵 add()、multiple() 和 invert()。然而,假设我们不想让外部可用——但内部需要——determinant()。
“保护”用户的一种方法是在矩阵的类声明中使行列式成为函数(def 语句)。然后保护它免受暴露。但是,如果他们知道内部结构,没有什么能阻止代码用户通过使用方法 matrix.determinant() 访问。
最后,很大程度上归结为惯例。公开一个接受两个矩阵的矩阵乘法函数更有意义,它被称为乘法(x,y)。至于行列式函数,与其将其“包装”在类中,不如将其定义为与矩阵的类定义相同级别的 __determinant(x) 更有意义。
您似乎永远无法通过声明来真正保护内部方法。您能做的最好的事情就是警告用户。“dunder”方法给出警告“预计不会在此文件中的代码之外调用它”。
推荐阅读
- php - Symfony 在使用 WSL2 的 Docker 中仍然很慢
- android - Android Navigation 无法与共享视图模型 mvvm 一起正常工作
- javascript - 如何访问具有 jQuery 事件的 HTML 元素的属性或方法
- javascript - 当“捆绑”关闭时,esbuild 不捆绑内部文件导入
- python - 如何比较一列的行值并更新另一列?
- html - ngx-bootstrap - 子组件中的手风琴组
- r - R dplyr 错误 mutate 问题 - 尝试按两列分组并用百分比改变新列
- firebase - 如何在 .where 子句中检查当前并升级到支持 != 运算符的 Firestore 版本
- c - c中的复数sigma表示法
- r - 为什么我不能安装 DMwR 包?