我正在尝试使用类重写一些代码。在某个时候,我想要的是使用对象的每个实例的参数值为成员函数分配特定的定义。

来自其他语言(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的代码更改为def sq(self):。实际上,Python tutorial 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 2this 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,并且函数本身被定义为对象原型(prototype)的成员或实例成员,然后使用... this进行正确分配。

编辑:
线程很长。对于那些寻求帮助的人,如果您是Python的新手,那么您可能需要检查选定的解决方案及其注释。但是,如果您已经了解Python中的绑定(bind)/未绑定(bind)方法,则只想按照Blckknght的答案中所述直接检查描述符的使用即可。我终于在我的代码中选择了这种方式,使用分配中的__get__来运行。

最佳答案

什么是self

在Python中,每个常规方法都必须接受通常称为self的参数。这是一个类的实例-一个对象。这就是Python方法与类状态交互的方式。

您可以根据自己的喜好重命名此参数。但它将始终具有相同的值:

>>> 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
>>>

这是因为Python中绑定(bind)的绑定(bind)的方法之间的区别。

当我们在__init__()中执行此操作时:
self.run = self.methods['method']

我们指的是未绑定(bind)方法method。这意味着我们对method的引用未绑定(bind)到Class的任何特定实例,因此,Python不会强制method接受对象实例。因为它没有人能给。

上面的代码与执行此操作相同:
>>> class Class:
    def method(foo):
        print(foo)


>>> Class.method(3)
3
>>>

在两个示例中,我们都调用类对象methodClass方法,而不是Class对象的实例。

通过检查repr的绑定(bind)和未绑定(bind)方法,我们可以进一步看到这种区别:
>>> 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>>
>>>

如您所见,在第一个示例中,当我们执行Class.method时,Python显示:<function Class.method at 0x03E43D68>。我对你撒了点谎。当我们拥有一个类的未绑定(bind)方法时,Python会将它们视为普通函数。因此method只是一个未绑定(bind)到`Class的任何实例的函数。

但是,在第二个示例中,当我们创建Class的实例,然后访问它的method对象时,我们看到了输出:<bound method Class.method of <__main__.Class object at 0x03BD2FB0>>

注意的关键部分是bound method Class.method。这意味着method,将绑定(bind)到cls-特定于Class的实例。

一般说明

正如@jonshapre所提到的,像在您的示例中那样编写代码会导致困惑(作为此问题的证明)和错误。如果您只是在nonLinearBipolarStep()之外定义Activation,然后从Activation.activation_functions内部引用它,那将是一个更好的主意:
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,
    }

    ...



如果您仍然想让nonLinearBipolarStep不受约束,那么我建议您小心一点。如果您认为您的方法可以编写最干净的代码,则可以这样做,但是请确保您知道自己在做什么以及代码将具有的行为。

如果您仍然想让类(class)用户清楚ag.run()是静态的,则可以在某个地方的文档字符串中对其进行文档记录,但这实际上是用户甚至根本不必关心的。

关于Python类方法: when is self not needed,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44741054/

10-14 01:12