为什么在没有 "self" 且没有装饰器的情况下声明 Python class 的方法不会引发异常?

Why is a method of a Python class declared without "self" and without decorators not raising an exception?

我认为以下代码会导致错误,因为据我所知,Python class 中的方法必须具有 "self"(或任何其他标签,但按照惯例 "self")作为它的第一个参数,或者如果使用 @classmethod 装饰器则为 "cls" 或类似的,或者如果使用 @staticmethod 装饰器则为 none用过。

为什么我在终端中使用 Python 3.5 没有错误 运行,即使 test_method 不符合这些要求?它作为静态方法似乎工作正常,但没有装饰器。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys

class MyClass:

    def test_method(args):
        print(args[1])

    @staticmethod
    def static_method():
        print("static_method")

    @classmethod
    def class_method(cls):
        print("class_method")


def main(args):
    MyClass.test_method(args)


if __name__ == '__main__':
    sys.exit(main(sys.argv))

输出:

$ python3 testscript.py "testing"
$ testing

编辑:

我的问题也可以用不同的措辞,将注意力从 self 转移到 @staticmethod:"How come I'm getting a seemingly working static method without the @staticmethod decorator?"

self 不一定是必需的。但是,如果您想引用与对象关联的任何变量或值(class 的实例化)(例如,对于关于汽车的 class,它是速度,self.speed)您您需要将 self 作为函数中的参数。出于这个原因,通常的做法是始终将 self 作为参数,否则您并没有真正出于正确的原因使用 class。

编辑: 如果您执行以下操作,这实际上会引发错误:

class a():
    def __init__(self, x):
        self.asd = x
    def hello(x):
        print(x)

>>> g = a(4)
>>> g.hello(5)

与调用"hello"时一样,"self"和“4”都将作为参数传递。它会在以下实例中工作,这就是我上面所说的:

>>> g = a
>>> g.hello(4)

>>> a.hello(4)

这没什么特别的。在 python 3 中,在 class 内部定义的函数与在 class 外部定义的函数没有区别。两者都是正常的功能。

您在这里谈论的 selfcls 只有在您通过 实例 访问函数时才会出现。因此在这里你没有得到任何错误。

但是,如果您将代码稍微修改为如下所示,则会收到预期的错误。

def main(args):
    MyClass().test_method(args)
    # Should throw an error

编辑:

  • @staticmethod 将适用于 class 实例,如 MyClass().test_method(args) 和常规直接调用,如 MyClass.test_method(args)
  • 但是,无法在 class 实例上调用常规方法(其中没有 self)。所以你总是必须将它称为 MyClass.test_method(args)

在Python2中,定义在class体中的函数会自动转换为"unbound methods",没有staticmethod装饰器不能直接调用。在Python3中,这个概念被去掉了; MyClass.text_method 是一个位于 MyClass 命名空间内的简单函数,可以直接调用。

在 Python 3 中仍然使用 staticmethod 的主要原因是如果您还想在 实例 上调用该方法。如果不使用装饰器,该方法将始终将实例作为第一个参数传递,从而导致 TypeError。

添加到此处的现有答案并提供代码示例:

class MyClass:
    def __init__(self):
        pass

    def myStaticMethod():
        print("a static method")

    @staticmethod
    def myStaticMethodWithArg(my_arg):
        print(my_arg)
        print("a static method")


MyClass.myStaticMethod()
MyClass.myStaticMethodWithArg("skhsdkj")
abc = MyClass()
abc.myStaticMethodWithArg("avc")

尝试删除 @staticmethod 装饰器并重新运行代码,看看会发生什么! (最后一次调用将失败,因为该方法在 self 和字符串输入中都被传递。通过添加装饰器,我们可以引导解释器执行我们想要的操作)