为什么声明 Python 类的方法没有"self",也没有装饰器不会引发异常?



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

为什么我在终端中使用 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:"为什么在没有@staticmethod装饰器的情况下,我得到了一个看似有效的静态方法?

在 Python 2 中,类体中定义的函数会自动转换为"未绑定方法",如果没有 staticmethod 装饰器,则无法直接调用。在 Python 3 中,这个概念被删除了;MyClass.text_method是位于 MyClass 命名空间内的简单函数,可以直接调用。

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

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

您在这里谈论的self或可能cls仅在通过实例访问函数时才会出现。因此,在这里您没有收到任何错误。

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

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

编辑:

  • @staticmethod将适用于两个类实例(如MyClass().test_method(args)(和常规直接调用(如MyClass.test_method(args)
  • 但是,常规方法(不含self(不能在类实例上调用。所以你总是必须称它为MyClass.test_method(args)

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

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

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)

要在此处添加现有答案并提供代码示例,请执行以下操作:

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和字符串输入中传递。通过添加装饰器,我们可以指导解释器执行我们想要的动作(

相关内容

最新更新