【问题标题】:Why is a method of a Python class declared without "self" and without decorators not raising an exception?为什么声明的 Python 类的方法没有“self”且没有装饰器不会引发异常?
【发布时间】:2019-03-20 18:07:11
【问题描述】:

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

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

#!/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 装饰器的情况下得到一个看似有效的静态方法?”

【问题讨论】:

  • 简短的回答是:在创建类的实例之前,它不是一种方法。它只是一个函数。试试 MyClass().text_method('test') 会报错。
  • @Jblasco 如果不是一个方法而只是一个函数,那么它与使用装饰器声明的静态方法有什么区别?
  • 也许这个问题的答案,你的query
  • 可以从类的实例@Theod'Or 访问方法。换句话说,这不能从实例中使用,只能从类本身中使用。

标签: python class methods static-methods class-method


【解决方案1】:

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

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

【讨论】:

  • 我接受了这个答案,因为它明确了 Python 2 和 3 之间的区别。这真的是让我感到震惊,我不知道发生了这种变化(有一段时间没有使用 Python)。谢谢!
  • “可以直接调用”是什么意思?我不必首先创建MyClass 类型的对象,我将在其上调用text_method()
【解决方案2】:

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

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

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

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)

【讨论】:

  • 在类中声明的普通函数与静态方法有何不同?
  • @Theod'Or 和 staticmethods 一样,唯一的区别是,你不能在类实例上调用它。
  • @jar 你知道Python为什么提供这两种静态方法吗? (有和没有装饰器),例如限制实例调用的充分理由是什么?
【解决方案3】:

self 不一定是必需的。但是,如果您想引用与对象关联的任何变量或值(类的实例化)(例如,关于汽车的类,它是速度,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)

【讨论】:

  • 这不是真的。 self is 是实例方法所必需的,即使你不使用它,因为它无论如何都会被传递;如果方法不接受它,你会得到一个 TypeError。
  • 你能给我一个抛出这个错误的代码的例子吗?因为以下原因:class a(): def hello(x): print(x) 工作正常
  • a.hello() 会起作用,但是您不会在实例上调用它,因此无论如何您都不希望拥有selfa().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 和字符串输入。通过添加装饰器,我们可以引导解释器执行我们想要的操作)

【讨论】:

    猜你喜欢
    • 2016-04-23
    • 2014-02-17
    • 2017-03-02
    • 1970-01-01
    • 2020-05-26
    • 2020-07-24
    • 2011-08-02
    • 1970-01-01
    • 2017-03-28
    相关资源
    最近更新 更多