Python类方法:何时不需要self
我试图用类重写一些代码。在某个时刻,我想要的是为成员函数指定一个特定的定义,使用对象的每个实例的参数值Python类方法:何时不需要self,python,Python,我试图用类重写一些代码。在某个时刻,我想要的是为成员函数指定一个特定的定义,使用对象的每个实例的参数值 来自其他语言(JavaScript、C++、Haskell、fortran……),我很难理解Python上的一些事情。一件事是类中self方法的以下区别 例如,以下代码显然不起作用: class fdf: def f(x): return 666 class gdg(fdf): def sq(): return 7*7 hg = gdg()
来自其他语言(JavaScript、C++、Haskell、fortran……),我很难理解Python上的一些事情。一件事是类中self方法的以下区别
例如,以下代码显然不起作用: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()接受0个位置参数,但给出了1”
据我所知,原因是在执行时,函数被传递到调用对象(调用sq的实例)的引用,作为我们可能定义/调用sq的任何其他参数/参数之前的第一个参数。因此,解决方案很简单:将sq的代码更改为defsq(self):
。事实上,这似乎表明对象方法应该始终以self
作为第一个参数来定义。这样我们得到了预期的6666649
。到目前为止还不错
但是,当我尝试实现我的类时,如下所示:
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))
self.run = self._getActivation(func).__get__(self)
然而,一种解决方法(解决方案??)是将没有参数self
(!)的步长函数定义为
然后我得到了1
的预期行为(至少对于这个简单的测试是这样)。因此,这里不仅不需要self
,而且它在这里甚至是不正确的用法
但是根据上面提到的教程,或者根据像或这样的线程中的答案,在我看来,这段代码不应该工作……或者在某个时候会产生一些意想不到的后果(?)。的确,如果我在\u getActivation
的定义中删除对self
的所有引用,我会收到错误消息\u getActivation()从0到1个位置参数中提取,但根据该规则,我可以理解其中2个位置参数
该线程没有向我提供一个明确的答案:上面代码的哪些语法细节告诉我不需要self
?例如,该代码与本教程示例有何不同
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
??实例化这个类的工作和预期的一样,但是如果没有定义,它会抱怨缺少参数(我知道它可能是任何标签)
这让我怀疑我的代码是否隐藏了定时炸弹:是否将self
作为x
的值传递?它如预期的那样工作,所以我会说不,但我面临着这个难题
我想我遗漏了这门语言的一些关键思想。我承认我也很难回答推荐人提出的问题
[^]:在JS中,只需在函数体中使用this
,函数本身被定义为对象原型的成员或实例成员,然后使用…this
正确分配
编辑:
这根线很长。对于那些浏览以获取帮助的人,如果您是Python新手,那么您可能需要检查所选的解决方案及其注释。然而,如果您已经了解Python中的绑定/未绑定方法,那么您只需要直接检查描述符的使用,如Blckknght的回答中所述。我最终在代码中选择了这种方式,在要运行的任务中使用了\uuuu get\uuuu
我认为让您感到困惑的是,您是通过class属性activationFunctions
来访问该方法的,而不是(作为一个实例通常会被访问)在实例本身上。例如,假设:
class Class:
def method(self, foo, bar):
print(self, foo, bar)
methods = {'method': method}
当我们直接从字典调用该方法时:
>>> Class.methods['method'](1, 2, 3)
1 2 3
您可以看到,我们将1
作为self
参数传递;没有对实例调用该方法,因此没有注入实例。相反,当我们在实例上调用它时:
>>> instance = Class()
>>> instance.method(1, 2)
<__main__.Class object at 0x...> 1 2
这可能不那么令人困惑。您在这段代码中使用的是未绑定方法(NonlinerBipolarStep):
activationFunctions = {
'bipolar': nonLinearBipolarStep ,
}
更详细的回答:方法是在类主体中定义的函数,并且总是至少接受一个参数,即所谓的self(除非您使用@staticfunction并将它们转换为普通函数)。Self是一个给定类的对象,在该类上调用方法(在C++中就是这样)。在python中,这个参数几乎没有什么特别之处,它不必命名为self。现在,当您调用unbound方法时,您给出的第一个参数将被解释为self并被使用。如果调用绑定方法,则不会发生这种消耗(该方法已具有其自身对象)。例如:
class A:
def foo(self, x): print(x)
a = A()
a.foo(1) # a.foo is bound method, a is self, prints 1
A.foo(a, 2) # A.foo is unbound method, first argument becomes self, prints 2
更新:
为什么它会起作用。简短回答:因为点(.)操作符会在可能的时候将unbound方法更新为bound
考虑一下,当您编写a.foo(1)时会发生什么。首先python检查对象a中的foo,没有发现任何内容(foo不是分配给a的值)。所以它进入一个类(名为a),瞧,foo就在那里并被使用。但这里有一个技巧。Python将把对象a绑定到未绑定的方法a.foo(细节我现在不知道了,想象一下dragon是这么做的),并将其绑定到绑定方法中。所以a.foo是绑定的,不再需要参数中的self,因此1进入参数x,一切都正常
现在让我们来看一下您的代码:您使用“bipolar”:映射中的非线性rbipolarstep,这是一种未绑定的方法。然后在构造函数(init)中将self.run设置为从_getActivation返回的值,该值取自activationFunctions映射。在给定的示例中,返回NonlinerBipolarStep unbound方法并将其分配给self.run。现在你叫ag.run。按照上一段中的逻辑,ag.run首先在ag对象内部查看。这是你的错误——它被发现了。由于python在ag对象中找到了ag.run值,所以它从未为运行对象查询过ag类型(激活),也从未有机会绑定它。所以ag.run是未绑定的方法,并希望首先使用自参数
通常有两种选择。要么执行ag.run(ag,4),这将起作用,但它很难看,要么手动将方法绑定到构造函数中的self。后者你可以做
activationFunctions = {
'bipolar': nonLinearBipolarStep ,
}
class A:
def foo(self, x): print(x)
a = A()
a.foo(1) # a.foo is bound method, a is self, prints 1
A.foo(a, 2) # A.foo is unbound method, first argument becomes self, prints 2
self.run = self._getActivation(func).__get__(self)
>>> class Class:
def method(foo): #
print(foo)
>>> cls = Class()
>>> cls.method()
<__main__.F object at 0x03E41D90>
>>>
>>> class Class:
def method(foo):
print(foo)
methods = {'method': method}
def __init__(self):
self.run = self.methods['method']
>>> cls = Class()
>>> cls.run(3)
3
>>>
self.run = self.methods['method']
>>> class Class:
def method(foo):
print(foo)
>>> Class.method(3)
3
>>>
>>> class Class:
def method(foo):
print(foo)
>>> Class.method
<function Class.method at 0x03E43D68>
>>> cls = Class()
>>> cls.method
<bound method Class.method of <__main__.Class object at 0x03BD2FB0>>
>>>
def nonLinearBipolarStep(self,x,string=None):
if not string: return (-1 if x<0 else 1 )
else: return ('-' if x<0 else '1')
class Activation:
activation_functions = {
'bipolar': nonLinearBipolarStep,
}
...
def __init__(self,func=None):
if func == None: func=self.default
self.run = types.MethodType(self._getActivation(func), self) # be sure to import types