我正在尝试使用类重写一些代码。在某些时候,我想要的是使用对象的每个实例的参数值为成员函数分配一个特定的定义。
来自其他语言(JavaScript、C++、Haskell、Fortran 等),我很难 理解 Python 上的一些东西。一件事是类方法中 自我 的以下区别。
例如,下面的代码显然是行不通的:
class fdf:
def f(x):
return 666
class gdg(fdf):
def sq():
return 7*7
hg = gdg()
hf = fdf()
print(hf.f(),hg.f(),hg.sq())
这给出了“ sq() takes 0 positional arguments but 1 was given ”的错误。
据我了解,原因是在 _执行时_,函数被传递给调用对象(调用 sq 的实例)的引用作为第一个参数,然后我们可能已经定义/调用了 sq 的任何其他参数/参数。所以解决方法很简单:把sq的代码 def sq(self):
。实际上, Python 教程 1 似乎 建议对象方法应始终使用 self
作为第一个参数来定义。这样做我们得到预期的 666 666 49
。到目前为止,一切都很好。
但是,当我尝试像这样实现我的课程时:
class Activation:
def nonLinearBipolarStep(self,x,string=None):
if not string: return (-1 if x<0 else 1 )
else: return ('-' if x<0 else '1')
default='bipolar'
activationFunctions = {
'bipolar': nonLinearBipolarStep ,
}
def _getActivation(self,func=default):
return self.activationFunctions.get(func,self.activationFunctions.get(self.default))
def __init__(self,func=None):
if func == None: func=self.default
self.run = self._getActivation(func)
ag = Activation()
print(ag.run(4))
我得到错误
nonLinearBipolarStep() missing 1 required positional argument: 'x'
然而,解决方法(解决方案??)正在定义不带参数 self
(!)的 step 函数
def nonLinearBipolarStep(x,string=None):
然后我得到预期的行为(至少对于这个简单的测试) 1
。因此,这里不仅不需要 self
, 而且在这里的使用也是不正确的!
但是根据上面提到的教程,或者像 this 2 或 this 3 这样的线程中的答案,在我看来这段代码不应该工作……或者应该在某些时候产生一些意想不到的后果(?)。 事实上,如果我在 self
的所有引用 _getActivation
我会收到错误消息 _getActivation() takes from 0 to 1 positional arguments but 2 were given
我可以根据规则理解。
线程 “Why is self not used in this method” 4 没有向我提供明确的答案:上面代码的哪些语法细节告诉我不需要 self
? 例如,该代码与本教程示例有何不同
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
?实例化此类按预期工作,但如果没有定义,它会抱怨缺少参数(我知道它可以是任何标签)。
这让我怀疑我的代码是否没有以某种方式隐藏定时炸弹: self
是否作为 x
的值传递?它按预期工作,所以我会说不,但后来我面临着这个难题。
我想我错过了该语言的一些关键思想。我承认我也在为参考文献 3 的 OP 提出的问题而苦恼^。
[^]: 在 JS 中,只需在函数体中使用 this
,并且函数本身被定义为对象原型的成员或实例成员,然后使用…正确分配它 this
。
编辑: 线程很长。对于那些浏览寻求帮助的人,如果您是 Python 的新手,那么您可能需要检查所选的解决方案及其注释。但是,如果您已经了解 Python 中的绑定/未绑定方法,您只想直接检查描述符的使用,如 Blckknght 的回答中所述。我最终在要运行的分配中使用 __get__
在我的代码中选择了这种方式。
原文由 MASL 发布,翻译遵循 CC BY-SA 4.0 许可协议
什么是
self
?在 Python 中,每个 普通 方法都被迫接受一个通常名为
self
的参数。这是类的一个实例——一个对象。这就是 Python 方法与类的状态交互的方式。您可以随意重命名此参数。但它将始终具有相同的值:
但是为什么我的例子有效呢?
但是,您可能对这段代码的工作方式有何不同感到困惑:
这是因为 Python 中 绑定 和 未绑定 方法之间的区别。
当我们在
__init__()
中这样做时:我们指的是 未绑定 方法
method
。这意味着我们对method
Class
任何 特定 实例,因此,Python 不会强制method
对象实例–。因为它没有可以给的。上面的代码与这样做是一样的:
在这两个示例中,我们都调用了类对象
Class
的方法method
--- ,而 不是Class
的 _实例_。我们可以通过检查绑定和未绑定方法的
repr
来进一步了解这种区别:如您所见,在第一个示例中,当我们执行
Class.method
时,Python 显示:<function Class.method at 0x03E43D68>
。我对你撒了一点谎。当我们有一个类的未绑定方法时,Python 将它们视为普通函数。所以method
只是一个未绑定到 `Class 的任何实例的函数。然而在第二个例子中,当我们创建
Class
的实例,然后访问它的method
对象时,我们看到打印:<bound method Class.method of <__main__.Class object at 0x03BD2FB0>>
要注意的关键部分是
bound method Class.method
。这意味着method
**绑定\*\* 到cls
-Class
的一个特定实例。一般说明
正如@jonshapre 所提到的,像您的示例中那样编写代码会导致混淆(作为这个问题的证明)和错误。如果您只是在
nonLinearBipolarStep()
之外 定义Activation
并从Activation.activation_functions
内部引用它,那将是一个更好的主意:如果您仍然想让
nonLinearBipolarStep
,那么我建议您要小心。如果你认为你的方法会产生最干净的代码,那就去做吧,但要确保你知道你在做什么以及你的代码将具有的行为。如果你仍然想让你的班级的用户清楚
ag.run()
是静态的,你 可以 在某个地方的文档字符串中记录它,但这是用户真的不应该关心的事情根本。