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