Python中@staticmethod和@classmethod有什么区别?

发布于 2024-07-06 08:14:16 字数 312 浏览 15 评论 0原文

装饰@staticmethod 和一个用 @classmethod

What is the difference between a method decorated with @staticmethod and one decorated with @classmethod?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

生寂 2024-07-13 08:14:16

也许一些示例代码会有所帮助:请注意 fooclass_foostatic_foo 的调用签名的差异:

class A(object):
    def foo(self, x):
        print(f"executing foo({self}, {x})")

    @classmethod
    def class_foo(cls, x):
        print(f"executing class_foo({cls}, {x})")

    @staticmethod
    def static_foo(x):
        print(f"executing static_foo({x})")

a = A()

下面是通常的方法对象实例调用方法。 对象实例 a 作为第一个参数隐式传递。

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)

使用类方法,对象实例的类将作为第一个参数隐式传递,而不是self

a.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)

您还可以使用该类调用class_foo。 事实上,如果你定义某件事
一个类方法,这可能是因为您打算从类而不是从类实例调用它。 A.foo(1) 会引发 TypeError,但 A.class_foo(1) 工作得很好:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)

人们发现类方法的一个用途是创建 可继承的替代构造函数


使用静态方法self(对象实例)和cls(类)都不会作为第一个参数隐式传递。 它们的行为类似于普通函数,只不过您可以从实例或类调用它们:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

静态方法用于将与类有某种逻辑联系的函数分组到类中。


foo 只是一个函数,但是当你调用 a.foo 时,你得到的不仅仅是函数,
您将获得该函数的“部分应用”版本,其中对象实例 a 绑定为该函数的第一个参数。 foo 需要 2 个参数,而 a.foo 仅需要 1 个参数。

a 绑定到 foo。 这就是下面术语“绑定”的含义:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

对于 a.class_fooa 并未绑定到 class_foo,而是绑定到类 < code>A 绑定到 class_foo

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

在这里,使用 staticmethod,即使它是一个方法,a.static_foo 也只是返回
一个很好的 'ole 函数,没有参数绑定。 static_foo 需要 1 个参数,并且
a.static_foo 也需要 1 个参数。

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

当然,当您使用类 A 调用 static_foo 时,也会发生同样的情况。

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

Maybe a bit of example code will help: Notice the difference in the call signatures of foo, class_foo and static_foo:

class A(object):
    def foo(self, x):
        print(f"executing foo({self}, {x})")

    @classmethod
    def class_foo(cls, x):
        print(f"executing class_foo({cls}, {x})")

    @staticmethod
    def static_foo(x):
        print(f"executing static_foo({x})")

a = A()

Below is the usual way an object instance calls a method. The object instance, a, is implicitly passed as the first argument.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)

With classmethods, the class of the object instance is implicitly passed as the first argument instead of self.

a.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)

You can also call class_foo using the class. In fact, if you define something to be
a classmethod, it is probably because you intend to call it from the class rather than from a class instance. A.foo(1) would have raised a TypeError, but A.class_foo(1) works just fine:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)

One use people have found for class methods is to create inheritable alternative constructors.


With staticmethods, neither self (the object instance) nor cls (the class) is implicitly passed as the first argument. They behave like plain functions except that you can call them from an instance or the class:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

Staticmethods are used to group functions which have some logical connection with a class to the class.


foo is just a function, but when you call a.foo you don't just get the function,
you get a "partially applied" version of the function with the object instance a bound as the first argument to the function. foo expects 2 arguments, while a.foo only expects 1 argument.

a is bound to foo. That is what is meant by the term "bound" below:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

With a.class_foo, a is not bound to class_foo, rather the class A is bound to class_foo.

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

Here, with a staticmethod, even though it is a method, a.static_foo just returns
a good 'ole function with no arguments bound. static_foo expects 1 argument, and
a.static_foo expects 1 argument too.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

And of course the same thing happens when you call static_foo with the class A instead.

print(A.static_foo)
# <function static_foo at 0xb7d479cc>
缪败 2024-07-13 08:14:16

静态方法是一种对调用它的类或实例一无所知的方法。 它只是获取传递的参数,没有隐式的第一个参数。

另一方面,类方法是一种将调用它的类或调用它的实例的类作为第一个参数传递的方法。 当您希望该方法成为类的工厂时,这非常有用:因为它获取作为第一个参数调用的实际类,所以您始终可以实例化正确的类,即使涉及子类也是如此。 例如,观察类方法 dict.fromkeys() 在子类上调用时如何返回子类的实例:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 

A staticmethod is a method that knows nothing about the class or instance it was called on. It just gets the arguments that were passed, no implicit first argument.

A classmethod, on the other hand, is a method that gets passed the class it was called on, or the class of the instance it was called on, as first argument. This is useful when you want the method to be a factory for the class: since it gets the actual class it was called on as first argument, you can always instantiate the right class, even when subclasses are involved. Observe for instance how dict.fromkeys(), a classmethod, returns an instance of the subclass when called on a subclass:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 
故事与诗 2024-07-13 08:14:16

基本上,@classmethod 创建一个方法,其第一个参数是调用它的类(而不是类实例),@staticmethod 没有任何隐式参数。

Basically @classmethod makes a method whose first argument is the class it's called from (rather than the class instance), @staticmethod does not have any implicit arguments.

兔小萌 2024-07-13 08:14:16

决定是否使用 @staticmethod@classmethod 你必须查看你的方法内部。 如果您的方法访问类中的其他变量/方法,则使用@classmethod。 另一方面,如果您的方法不涉及类的任何其他部分,则使用@staticmethod。

class Apple:

    _counter = 0

    @staticmethod
    def about_apple():
        print('Apple is good for you.')

        # note you can still access other member of the class
        # but you have to use the class instance 
        # which is not very nice, because you have repeat yourself
        # 
        # For example:
        # @staticmethod
        #    print('Number of apples have been juiced: %s' % Apple._counter)
        #
        # @classmethod
        #    print('Number of apples have been juiced: %s' % cls._counter)
        #
        #    @classmethod is especially useful when you move your function to another class,
        #       you don't have to rename the referenced class 

    @classmethod
    def make_apple_juice(cls, number_of_apples):
        print('Making juice:')
        for i in range(number_of_apples):
            cls._juice_this(i)

    @classmethod
    def _juice_this(cls, apple):
        print('Juicing apple %d...' % apple)
        cls._counter += 1

To decide whether to use @staticmethod or @classmethod you have to look inside your method. If your method accesses other variables/methods in your class then use @classmethod. On the other hand, if your method does not touches any other parts of the class then use @staticmethod.

class Apple:

    _counter = 0

    @staticmethod
    def about_apple():
        print('Apple is good for you.')

        # note you can still access other member of the class
        # but you have to use the class instance 
        # which is not very nice, because you have repeat yourself
        # 
        # For example:
        # @staticmethod
        #    print('Number of apples have been juiced: %s' % Apple._counter)
        #
        # @classmethod
        #    print('Number of apples have been juiced: %s' % cls._counter)
        #
        #    @classmethod is especially useful when you move your function to another class,
        #       you don't have to rename the referenced class 

    @classmethod
    def make_apple_juice(cls, number_of_apples):
        print('Making juice:')
        for i in range(number_of_apples):
            cls._juice_this(i)

    @classmethod
    def _juice_this(cls, apple):
        print('Juicing apple %d...' % apple)
        cls._counter += 1
懒的傷心 2024-07-13 08:14:16

官方 python 文档:

@classmethod

类方法接收类作为
隐式第一个参数,就像
实例方法接收实例。
要声明类方法,请使用此
成语:

<前><代码>C类:
@类方法
def f(cls, arg1, arg2, ...): ...

@classmethod 形式是一个函数
装饰器 – 请参阅以下描述
Function 中的函数定义
定义
了解详细信息。

它可以在类上调用
(例如 Cf())或在实例上
(例如C().f())。 实例是
除了它的类之外被忽略。 如果一个
为派生类调用类方法
类,派生类对象是
作为隐含的第一个参数传递。

类方法与 C++ 不同
或 Java 静态方法。 如果你想
这些,请参阅此中的 staticmethod()
部分。

@staticmethod

静态方法不接收
隐含的第一个参数。 声明一个
静态方法,使用这个习惯用法:

<前><代码>C类:
@静态方法
def f(arg1, arg2, ...): ...

@staticmethod 形式是一个函数
装饰器 – 请参阅以下描述
Function 中的函数定义
定义
了解详细信息。

它可以在类上调用
(例如 Cf())或在实例上
(例如C().f())。 实例是
除了它的类之外被忽略。

Python中的静态方法类似
那些在 Java 或 C++ 中找到的。 为一个
更先进的概念,请参见
classmethod() 在本节中。< /p>

Official python docs:

@classmethod

A class method receives the class as
implicit first argument, just like an
instance method receives the instance.
To declare a class method, use this
idiom:

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 

The @classmethod form is a function
decorator – see the description of
function definitions in Function
definitions
for details.

It can be called either on the class
(such as C.f()) or on an instance
(such as C().f()). The instance is
ignored except for its class. If a
class method is called for a derived
class, the derived class object is
passed as the implied first argument.

Class methods are different than C++
or Java static methods. If you want
those, see staticmethod() in this
section.

@staticmethod

A static method does not receive an
implicit first argument. To declare a
static method, use this idiom:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 

The @staticmethod form is a function
decorator – see the description of
function definitions in Function
definitions
for details.

It can be called either on the class
(such as C.f()) or on an instance
(such as C().f()). The instance is
ignored except for its class.

Static methods in Python are similar
to those found in Java or C++. For a
more advanced concept, see
classmethod() in this section.

晨曦÷微暖 2024-07-13 08:14:16

这里是关于这个问题的一篇简短文章

@staticmethod 函数只不过是在类内部定义的函数。 无需先实例化该类即可调用它。 它的定义通过继承是不可变的。

@classmethod 函数也可以在不实例化类的情况下调用,但它的定义通过继承遵循子类,而不是父类。 这是因为 @classmethod 函数的第一个参数必须始终是 cls(类)。

Here is a short article on this question

@staticmethod function is nothing more than a function defined inside a class. It is callable without instantiating the class first. It’s definition is immutable via inheritance.

@classmethod function also callable without instantiating the class, but its definition follows Sub class, not Parent class, via inheritance. That’s because the first argument for @classmethod function must always be cls (class).

一指流沙 2024-07-13 08:14:16

Python中@staticmethod和@classmethod有什么区别?

您可能已经看过像这样的伪代码的 Python 代码,它演示了各种方法类型的签名,并提供了文档字符串来解释每种方法类型:

class Foo(object):

    def a_normal_instance_method(self, arg_1, kwarg_2=None):
        '''
        Return a value that is a function of the instance with its
        attributes, and other arguments such as arg_1 and kwarg2
        '''

    @staticmethod
    def a_static_method(arg_0):
        '''
        Return a value that is a function of arg_0. It does not know the 
        instance or class it is called from.
        '''

    @classmethod
    def a_class_method(cls, arg1):
        '''
        Return a value that is a function of the class and other arguments.
        respects subclassing, it is called with the class it is called from.
        '''

普通实例方法

首先我将解释 a_normal_instance_method。 这准确地称为“实例方法”。 当使用实例方法时,它被用作部分函数(与在源代码中查看时为所有值定义的总函数相反),也就是说,在使用时,第一个参数被预定义为该实例的实例。对象,及其所有给定的属性。 它绑定了对象的实例,并且必须从对象的实例调用它。 通常,它将访问实例的各种属性。

例如,这是一个字符串的实例:

', '

如果我们在此字符串上使用实例方法 join 来连接另一个可迭代对象,
很明显,它是实例的函数,除了是可迭代列表的函数之外,['a', 'b', 'c']:

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'

绑定方法

实例方法可以通过以下方式绑定点式查找供稍后使用。

例如,这将 str.join 方法绑定到 ':' 实例:

>>> join_with_colons = ':'.join 

稍后我们可以将其用作已绑定第一个参数的函数。 通过这种方式,它的工作方式就像实例上的部分函数:

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'

静态方法

静态方法将实例作为参数。

它与模块级功能非常相似。

但是,模块级函数必须存在于模块中,并专门导入到使用它的其他地方。

但是,如果它附加到对象,它也将通过导入和继承方便地跟随对象。

静态方法的一个示例是 str.maketrans,它是从 Python 3 中的 string 模块移出的。它使翻译表适合 str.translate< 使用/代码>。 当从字符串实例使用时,它看起来确实相当愚蠢,如下所示,但是从 string 模块导入该函数相当笨拙,并且能够从类中调用它真是太好了,如 str.maketrans

# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}

在 python 2 中,您必须从越来越不那么有用的字符串模块中导入此函数:

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'

类方法

类方法与实例方法类似,因为它采用隐式第一个参数,但它不是采用实例,而是采用类。 它们经常被用作替代构造函数以获得更好的语义使用,并且它将支持继承。

内置类方法最典型的示例是 dict.fromkeys。 它被用作 dict 的替代构造函数(非常适合当您知道键是什么并且想要它们的默认值时。)

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}

当我们子类 dict 时,我们可以使用相同的构造函数,它创建子类的实例。

>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>

有关其他类似的替代示例,请参阅 pandas 源代码构造函数,另请参阅有关 classmethodstaticmethod

What is the difference between @staticmethod and @classmethod in Python?

You may have seen Python code like this pseudocode, which demonstrates the signatures of the various method types and provides a docstring to explain each:

class Foo(object):

    def a_normal_instance_method(self, arg_1, kwarg_2=None):
        '''
        Return a value that is a function of the instance with its
        attributes, and other arguments such as arg_1 and kwarg2
        '''

    @staticmethod
    def a_static_method(arg_0):
        '''
        Return a value that is a function of arg_0. It does not know the 
        instance or class it is called from.
        '''

    @classmethod
    def a_class_method(cls, arg1):
        '''
        Return a value that is a function of the class and other arguments.
        respects subclassing, it is called with the class it is called from.
        '''

The Normal Instance Method

First I'll explain a_normal_instance_method. This is precisely called an "instance method". When an instance method is used, it is used as a partial function (as opposed to a total function, defined for all values when viewed in source code) that is, when used, the first of the arguments is predefined as the instance of the object, with all of its given attributes. It has the instance of the object bound to it, and it must be called from an instance of the object. Typically, it will access various attributes of the instance.

For example, this is an instance of a string:

', '

if we use the instance method, join on this string, to join another iterable,
it quite obviously is a function of the instance, in addition to being a function of the iterable list, ['a', 'b', 'c']:

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'

Bound methods

Instance methods can be bound via a dotted lookup for use later.

For example, this binds the str.join method to the ':' instance:

>>> join_with_colons = ':'.join 

And later we can use this as a function that already has the first argument bound to it. In this way, it works like a partial function on the instance:

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'

Static Method

The static method does not take the instance as an argument.

It is very similar to a module level function.

However, a module level function must live in the module and be specially imported to other places where it is used.

If it is attached to the object, however, it will follow the object conveniently through importing and inheritance as well.

An example of a static method is str.maketrans, moved from the string module in Python 3. It makes a translation table suitable for consumption by str.translate. It does seem rather silly when used from an instance of a string, as demonstrated below, but importing the function from the string module is rather clumsy, and it's nice to be able to call it from the class, as in str.maketrans

# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}

In python 2, you have to import this function from the increasingly less useful string module:

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'

Class Method

A class method is a similar to an instance method in that it takes an implicit first argument, but instead of taking the instance, it takes the class. Frequently these are used as alternative constructors for better semantic usage and it will support inheritance.

The most canonical example of a builtin classmethod is dict.fromkeys. It is used as an alternative constructor of dict, (well suited for when you know what your keys are and want a default value for them.)

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}

When we subclass dict, we can use the same constructor, which creates an instance of the subclass.

>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>

See the pandas source code for other similar examples of alternative constructors, and see also the official Python documentation on classmethod and staticmethod.

如梦 2024-07-13 08:14:16

我开始学习 C++ 编程语言,然后是 Java,然后是 Python,所以这个问题也让我很困扰,直到我理解了每种语言的简单用法。

类方法:与 Java 和 C++ 不同,Python 没有构造函数重载。 因此,要实现此目的,您可以使用classmethod。 下面的示例将解释这一点

让我们假设我们有一个 Person 类,它接受两个参数 first_namelast_name 并创建 Person< 的实例/代码>。

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

现在,如果您需要仅使用单个名称(即 first_name)创建一个类,那么您不能在 Python 中执行类似的操作。

当您尝试创建对象(实例)时,这会给您带来错误。

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

但是,您可以使用 @classmethod 实现相同的效果,如下所述

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

静态方法: 这相当简单,它不绑定到实例或类,您可以简单地使用班级名称。

因此,假设在上面的示例中,您需要验证 first_name 不应超过 20 个字符,您可以简单地执行此操作。

@staticmethod  
def validate_name(name):
    return len(name) <= 20

您可以简单地使用类名进行调用

Person.validate_name("Gaurang Shah")

I started learning programming language with C++ and then Java and then Python and so this question bothered me a lot as well, until I understood the simple usage of each.

Class Method: Python unlike Java and C++ doesn't have constructor overloading. And so to achieve this you could use classmethod. Following example will explain this

Let's consider we have a Person class which takes two arguments first_name and last_name and creates the instance of Person.

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

Now, if the requirement comes where you need to create a class using a single name only, just a first_name, you can't do something like this in Python.

This will give you an error when you will try to create an object (instance).

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

However, you could achieve the same thing using @classmethod as mentioned below

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

Static Method: This is rather simple, it's not bound to instance or class and you can simply call that using class name.

So let's say in above example you need a validation that first_name should not exceed 20 characters, you can simply do this.

@staticmethod  
def validate_name(name):
    return len(name) <= 20

and you could simply call using class name

Person.validate_name("Gaurang Shah")
甜心 2024-07-13 08:14:16

只有第一个参数不同

  • 普通方法:当前对象自动作为(附加)第一个参数传递
  • 类方法:当前对象的类 > 作为(附加)第一个参数
  • 静态方法自动传递:没有额外的参数自动传递。 你传递给函数的就是你得到的。

更详细地说...

普通方法

“标准”方法,就像在每种面向对象语言中一样。 当调用对象的方法时,会自动为其提供一个额外的参数 self 作为其第一个参数。 也就是说,

def f(self, x, y)

必须使用 2 个参数调用方法。 self 是自动传递的,它是对象本身。 类似于神奇地出现在eg中的this。 java/c++,仅在python中明确显示。

实际上,第一个参数不必被称为self,但这是标准约定,所以保留它

类方法

当方法被装饰时

@classmethod
def f(cls, x, y)

自动提供的参数不是 self,而是self的类

静态方法

当该方法被修饰时,

@staticmethod
def f(x, y)

该方法根本不会被赋予任何自动参数。 仅给出调用它时使用的参数。

用法

  • classmethod 主要用于替代构造函数。
  • staticmethod 不使用对象的状态,甚至不使用类本身的结构。 它可以是类的外部函数。 它只放在类内部,用于对具有相似功能的函数进行分组(例如,像 Java 的 Math 类静态方法)
class Point
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def frompolar(cls, radius, angle):
        """The `cls` argument is the `Point` class itself"""
        return cls(radius * cos(angle), radius * sin(angle))

    @staticmethod
    def angle(x, y):
        """this could be outside the class, but we put it here 
just because we think it is logically related to the class."""
        return atan(y, x)


p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)

angle = Point.angle(3, 2)

Only the first argument differs:

  • normal method: the current object is automatically passed as an (additional) first argument
  • classmethod: the class of the current object is automatically passed as an (additional) fist argument
  • staticmethod: no extra arguments are automatically passed. What you passed to the function is what you get.

In more detail...

normal method

The "standard" method, as in every object oriented language. When an object's method is called, it is automatically given an extra argument self as its first argument. That is, method

def f(self, x, y)

must be called with 2 arguments. self is automatically passed, and it is the object itself. Similar to the this that magically appears in eg. java/c++, only in python it is shown explicitly.

actually, the first argument does not have to be called self, but it's the standard convention, so keep it

class method

When the method is decorated

@classmethod
def f(cls, x, y)

the automatically provided argument is not self, but the class of self.

static method

When the method is decorated

@staticmethod
def f(x, y)

the method is not given any automatic argument at all. It is only given the parameters that it is called with.

usages

  • classmethod is mostly used for alternative constructors.
  • staticmethod does not use the state of the object, or even the structure of the class itself. It could be a function external to a class. It only put inside the class for grouping functions with similar functionality (for example, like Java's Math class static methods)
class Point
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def frompolar(cls, radius, angle):
        """The `cls` argument is the `Point` class itself"""
        return cls(radius * cos(angle), radius * sin(angle))

    @staticmethod
    def angle(x, y):
        """this could be outside the class, but we put it here 
just because we think it is logically related to the class."""
        return atan(y, x)


p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)

angle = Point.angle(3, 2)

我ぃ本無心為│何有愛 2024-07-13 08:14:16

我认为更好的问题是“你什么时候使用@classmethod vs @staticmethod?”

@classmethod 允许您轻松访问与类定义关联的私有成员。 这是实现单例或控制所创建对象的实例数量的工厂类的好方法。

@staticmethod 提供了边际性能提升,但我还没有看到在类中有效使用静态方法而无法在类外部作为独立函数实现。

I think a better question is "When would you use @classmethod vs @staticmethod?"

@classmethod allows you easy access to private members that are associated to the class definition. this is a great way to do singletons, or factory classes that control the number of instances of the created objects exist.

@staticmethod provides marginal performance gains, but I have yet to see a productive use of a static method within a class that couldn't be achieved as a standalone function outside the class.

初心 2024-07-13 08:14:16

静态方法:

  • 没有自变量的简单函数。
  • 研究类属性; 不在实例属性上。
  • 可以通过类和实例调用。
  • 内置函数 staticmethod() 用于创建它们。

静态方法的好处:

  • 它将函数名称本地化在类作用域中
  • 它将函数代码移动到更接近其使用位置的位置
  • 与模块级函数相比,导入更方便,因为每个方法都不必专门进口

    <前><代码>@staticmethod
    def some_static_method(*args, **kwds):
    经过

类方法:

  • 第一个参数作为类名的函数。
  • 可以通过类和实例调用。
  • 这些是使用 classmethod 内置函数创建的。

    <前><代码> @classmethod
    def some_class_method(cls, *args, **kwds):
    经过

Static Methods:

  • Simple functions with no self argument.
  • Work on class attributes; not on instance attributes.
  • Can be called through both class and instance.
  • The built-in function staticmethod()is used to create them.

Benefits of Static Methods:

  • It localizes the function name in the classscope
  • It moves the function code closer to where it is used
  • More convenient to import versus module-level functions since each method does not have to be specially imported

    @staticmethod
    def some_static_method(*args, **kwds):
        pass
    

Class Methods:

  • Functions that have first argument as classname.
  • Can be called through both class and instance.
  • These are created with classmethod in-built function.

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass
    
很糊涂小朋友 2024-07-13 08:14:16

@decorators 是在 python 2.4 中添加的如果你使用的是 python < 2.4 可以使用classmethod()和staticmethod()函数。

例如,如果您想创建一个工厂方法(一个函数,根据它获取的参数返回类的不同实现的实例),您可以执行以下操作:

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

另请注意,这是使用类方法的一个很好的示例,并且静态方法,
静态方法显然属于该类,因为它在内部使用类 Cluster。
类方法只需要有关类的信息,不需要对象的实例。

将 _is_cluster_for 方法作为类方法的另一个好处是,子类可以决定更改其实现,也许是因为它非常通用并且可以处理多种类型的集群,因此只需检查该类的名称即可类还不够。

@decorators were added in python 2.4 If you're using python < 2.4 you can use the classmethod() and staticmethod() function.

For example, if you want to create a factory method (A function returning an instance of a different implementation of a class depending on what argument it gets) you can do something like:

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

Also observe that this is a good example for using a classmethod and a static method,
The static method clearly belongs to the class, since it uses the class Cluster internally.
The classmethod only needs information about the class, and no instance of the object.

Another benefit of making the _is_cluster_for method a classmethod is so a subclass can decide to change it's implementation, maybe because it is pretty generic and can handle more than one type of cluster, so just checking the name of the class would not be enough.

追星践月 2024-07-13 08:14:16

我先说说@classmethod和@staticmethod修饰的方法之间的相似之处。

相似之处:它们都可以在本身上调用,而不仅仅是类的实例。 所以,从某种意义上说,它们都是类的方法。

区别:类方法将接收类本身作为第一个参数,而静态方法则不会。

因此,从某种意义上说,静态方法并不绑定到类本身,只是因为它可能具有相关功能而挂在那里。

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)

Let me tell the similarity between a method decorated with @classmethod vs @staticmethod first.

Similarity: Both of them can be called on the Class itself, rather than just the instance of the class. So, both of them in a sense are Class's methods.

Difference: A classmethod will receive the class itself as the first argument, while a staticmethod does not.

So a static method is, in a sense, not bound to the Class itself and is just hanging in there just because it may have a related functionality.

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)
猫卆 2024-07-13 08:14:16

@staticmethod 只是禁用默认函数作为方法描述符。 classmethod 将您的函数包装在一个可调用容器中,该容器可调用对象传递对所属类的引用作为第一个参数:

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

事实上,classmethod 具有运行时开销,但可以访问所属类。 或者,我建议使用元类并将类方法放在该元类上:

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>

@staticmethod just disables the default function as method descriptor. classmethod wraps your function in a container callable that passes a reference to the owning class as first argument:

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

As a matter of fact, classmethod has a runtime overhead but makes it possible to access the owning class. Alternatively I recommend using a metaclass and putting the class methods on that metaclass:

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>
余生再见 2024-07-13 08:14:16

有关如何在 Python 中使用静态、类或抽象方法的权威指南是该主题的一个很好的链接,并将其总结如下。

@staticmethod 函数只不过是在类内部定义的函数。 无需先实例化该类即可调用它。 它的定义通过继承是不可变的。

  • Python 不必实例化对象的绑定方法。
  • 它简化了代码的可读性,并且不依赖于对象本身的状态;

@classmethod 函数也可以在不实例化类的情况下调用,但它的定义遵循子类,而不是父类,通过继承,可以被子类覆盖。 这是因为 @classmethod 函数的第一个参数必须始终是 cls(类)。

  • 工厂方法,用于使用例如某种预处理来创建类的实例。
  • 静态方法调用静态方法:如果将一个静态方法拆分为多个静态方法,则不应硬编码类名,而应使用类方法

The definitive guide on how to use static, class or abstract methods in Python is one good link for this topic, and summary it as following.

@staticmethod function is nothing more than a function defined inside a class. It is callable without instantiating the class first. It’s definition is immutable via inheritance.

  • Python does not have to instantiate a bound-method for object.
  • It eases the readability of the code, and it does not depend on the state of object itself;

@classmethod function also callable without instantiating the class, but its definition follows Sub class, not Parent class, via inheritance, can be overridden by subclass. That’s because the first argument for @classmethod function must always be cls (class).

  • Factory methods, that are used to create an instance for a class using for example some sort of pre-processing.
  • Static methods calling static methods: if you split a static methods in several static methods, you shouldn't hard-code the class name but use class methods
似最初 2024-07-13 08:14:16

关于静态方法与类方法的另一个考虑因素是继承。 假设您有以下类:

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"

然后您想在子类中重写 bar()

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"

这可行,但请注意,现在子类中的 bar() 实现类 (Foo2) 无法再利用该类特有的任何内容。 例如,假设 Foo2 有一个名为 magic() 的方法,您希望在 bar()< 的 Foo2 实现中使用该方法。 /code>:

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
    @staticmethod
    def magic():
        return "Something useful you'd like to use in bar, but now can't" 

这里的解决方法是在 bar() 中调用 Foo2.magic(),但随后您会重复自己(如果 的名称Foo2 发生变化,您必须记住更新该 bar() 方法)。

对我来说,这稍微违反了开放/封闭原则,因为做出了决定in Foo 正在影响您在派生类中重构公共代码的能力(即它对扩展的开放程度较低)。 如果 bar() 是一个 classmethod 我们就可以了:

class Foo(object):
    @classmethod
    def bar(cls):
        return "In Foo"

class Foo2(Foo):
    @classmethod
    def bar(cls):
        return "In Foo2 " + cls.magic()
    @classmethod
    def magic(cls):
        return "MAGIC"

print Foo2().bar()

给出:In Foo2 MAGIC

另外:历史记录:Guido Van Rossum(Python 的创建者) )曾经将 staticmethod 称为“意外”:https://mail.python.org/pipermail/python-ideas/2012-May/014969.html

我们都知道静态方法有多么有限。 (它们基本上是一个意外——早在 Python 2.2 时代,当我发明新式类和描述符时,我打算实现类方法,但一开始我不理解它们,并且意外地先实现了静态方法。然后它来不及删除它们并仅提供类方法。

https ://mail.python.org/pipermail/python-ideas/2016-July/041189.html

老实说,staticmethod 是一个错误——我试图做一些类似于 Java 类方法的事情,但是一旦它发布,我发现真正需要的是 classmethod。 但摆脱 staticmethod 已经太晚了。

Another consideration with respect to staticmethod vs classmethod comes up with inheritance. Say you have the following class:

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"

And you then want to override bar() in a child class:

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"

This works, but note that now the bar() implementation in the child class (Foo2) can no longer take advantage of anything specific to that class. For example, say Foo2 had a method called magic() that you want to use in the Foo2 implementation of bar():

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
    @staticmethod
    def magic():
        return "Something useful you'd like to use in bar, but now can't" 

The workaround here would be to call Foo2.magic() in bar(), but then you're repeating yourself (if the name of Foo2 changes, you'll have to remember to update that bar() method).

To me, this is a slight violation of the open/closed principle, since a decision made in Foo is impacting your ability to refactor common code in a derived class (ie it's less open to extension). If bar() were a classmethod we'd be fine:

class Foo(object):
    @classmethod
    def bar(cls):
        return "In Foo"

class Foo2(Foo):
    @classmethod
    def bar(cls):
        return "In Foo2 " + cls.magic()
    @classmethod
    def magic(cls):
        return "MAGIC"

print Foo2().bar()

Gives: In Foo2 MAGIC

Also: historical note: Guido Van Rossum (Python's creator) once referred to staticmethod's as "an accident": https://mail.python.org/pipermail/python-ideas/2012-May/014969.html

we all know how limited static methods are. (They're basically an accident -- back in the Python 2.2 days when I was inventing new-style classes and descriptors, I meant to implement class methods but at first I didn't understand them and accidentally implemented static methods first. Then it was too late to remove them and only provide class methods.

Also: https://mail.python.org/pipermail/python-ideas/2016-July/041189.html

Honestly, staticmethod was something of a mistake -- I was trying to do something like Java class methods but once it was released I found what was really needed was classmethod. But it was too late to get rid of staticmethod.

涙—继续流 2024-07-13 08:14:16

当存在继承时就会出现差异。

假设有两个类 - ParentChild。 如果要使用@staticmethodprint_name方法应该写两次,因为类的名称应该写在打印行中。

class Parent:
   _class_name = "Parent"

   @staticmethod
   def print_name():
       print(Parent._class_name)


class Child(Parent):
   _class_name = "Child"

   @staticmethod
   def print_name():
       print(Child._class_name)


Parent.print_name()
Child.print_name()

但是,对于@classmethod,不需要写两次print_name方法。

class Parent:
    _class_name = "Parent"

    @classmethod
    def print_name(cls):
        print(cls._class_name)


class Child(Parent):
    _class_name = "Child"


Parent.print_name()
Child.print_name()

The difference occurs when there is inheritance.

Suppose that there are two classes -- Parent and Child. If one wants to use @staticmethod, print_name method should be written twice because the name of the class should be written in the print line.

class Parent:
   _class_name = "Parent"

   @staticmethod
   def print_name():
       print(Parent._class_name)


class Child(Parent):
   _class_name = "Child"

   @staticmethod
   def print_name():
       print(Child._class_name)


Parent.print_name()
Child.print_name()

However, for @classmethod, it is not required to write print_name method twice.

class Parent:
    _class_name = "Parent"

    @classmethod
    def print_name(cls):
        print(cls._class_name)


class Child(Parent):
    _class_name = "Child"


Parent.print_name()
Child.print_name()
少女情怀诗 2024-07-13 08:14:16

实例方法

+ 可以修改对象实例状态

+ 可以< /em> 修改类状态

类方法

- 无法修改对象实例状态

+< /code> 可以修改类状态

静态方法

- 不能修改对象实例状态

- 无法修改类状态

class MyClass:
    ''' 
    Instance method has a mandatory first attribute self which represent the instance itself. 
    Instance method must be called by a instantiated instance.
    '''
    def method(self):
        return 'instance method called', self
    
    '''
    Class method has a mandatory first attribute cls which represent the class itself. 
    Class method can be called by an instance or by the class directly. 
    Its most common using scenario is to define a factory method.
    '''
    @classmethod
    def class_method(cls):
        return 'class method called', cls
    
    '''
    Static method doesn’t have any attributes of instances or the class. 
    It also can be called by an instance or by the class directly. 
    Its most common using scenario is to define some helper or utility functions which are closely relative to the class.
    '''
    @staticmethod
    def static_method():
        return 'static method called'


obj = MyClass()
print(obj.method())
print(obj.class_method()) # MyClass.class_method()
print(obj.static_method()) # MyClass.static_method()

输出:

('instance method called', <__main__.MyClass object at 0x100fb3940>)
('class method called', <class '__main__.MyClass'>)
static method called

我们实际上可以访问对象实例的实例方法,所以这是我的类对象的实例,而通过类方法,我们可以访问类本身。 但不适用于任何对象,因为类方法并不真正关心对象是否存在。 但是,您可以在对象实例上调用类方法和静态方法。 这会起作用,但实际上并没有什么区别,所以当你在这里调用静态方法时,它会起作用,并且它会知道你想调用哪个方法。

静态方法用于执行一些实用任务,类方法用于工厂方法。 工厂方法可以为不同的用例返回类对象。

最后,为了更好地理解一个简短的例子:

class Student:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_from_string(cls, name_string: str):
        first_name, last_name = name_string.split()
        if Student.validate_name(first_name) and Student.validate_name(last_name):
            return cls(first_name, last_name)
        else:
            print('Invalid Names')

    @staticmethod
    def validate_name(name):
        return len(name) <= 10


stackoverflow_student = Student.get_from_string('Name Surname')
print(stackoverflow_student.first_name) # Name
print(stackoverflow_student.last_name) # Surname

Instance Method:

+ Can modify object instance state

+ Can modify class state

Class Method:

- Can't modify object instance state

+ Can modify class state

Static Method:

- Can't modify object instance state

- Can't modify class state

class MyClass:
    ''' 
    Instance method has a mandatory first attribute self which represent the instance itself. 
    Instance method must be called by a instantiated instance.
    '''
    def method(self):
        return 'instance method called', self
    
    '''
    Class method has a mandatory first attribute cls which represent the class itself. 
    Class method can be called by an instance or by the class directly. 
    Its most common using scenario is to define a factory method.
    '''
    @classmethod
    def class_method(cls):
        return 'class method called', cls
    
    '''
    Static method doesn’t have any attributes of instances or the class. 
    It also can be called by an instance or by the class directly. 
    Its most common using scenario is to define some helper or utility functions which are closely relative to the class.
    '''
    @staticmethod
    def static_method():
        return 'static method called'


obj = MyClass()
print(obj.method())
print(obj.class_method()) # MyClass.class_method()
print(obj.static_method()) # MyClass.static_method()

output:

('instance method called', <__main__.MyClass object at 0x100fb3940>)
('class method called', <class '__main__.MyClass'>)
static method called

The instance method we actually had access to the object instance , right so this was an instance off a my class object whereas with the class method we have access to the class itself. But not to any of the objects, because the class method doesn't really care about an object existing. However you can both call a class method and static method on an object instance. This is going to work it doesn't really make a difference, so again when you call static method here it's going to work and it's going to know which method you want to call.

The Static methods are used to do some utility tasks, and class methods are used for factory methods. The factory methods can return class objects for different use cases.

And finally, a short example for better understanding:

class Student:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_from_string(cls, name_string: str):
        first_name, last_name = name_string.split()
        if Student.validate_name(first_name) and Student.validate_name(last_name):
            return cls(first_name, last_name)
        else:
            print('Invalid Names')

    @staticmethod
    def validate_name(name):
        return len(name) <= 10


stackoverflow_student = Student.get_from_string('Name Surname')
print(stackoverflow_student.first_name) # Name
print(stackoverflow_student.last_name) # Surname
流殇 2024-07-13 08:14:16

我将尝试用一个例子来解释基本的区别。

class A(object):
    x = 0

    def say_hi(self):
        pass

    @staticmethod
    def say_hi_static():
        pass

    @classmethod
    def say_hi_class(cls):
        pass

    def run_self(self):
        self.x += 1
        print self.x # outputs 1
        self.say_hi()
        self.say_hi_static()
        self.say_hi_class()

    @staticmethod
    def run_static():
        print A.x  # outputs 0
        # A.say_hi() #  wrong
        A.say_hi_static()
        A.say_hi_class()

    @classmethod
    def run_class(cls):
        print cls.x # outputs 0
        # cls.say_hi() #  wrong
        cls.say_hi_static()
        cls.say_hi_class()

1 - 我们可以直接调用静态方法和类方法,而不需要初始化

# A.run_self() #  wrong
A.run_static()
A.run_class()

2 - 静态方法不能调用 self 方法,但可以调用其他静态方法和类方法

3 - 静态方法属于类,根本不会使用对象。

4-类方法不绑定到对象,而是绑定到类。

I will try to explain the basic difference using an example.

class A(object):
    x = 0

    def say_hi(self):
        pass

    @staticmethod
    def say_hi_static():
        pass

    @classmethod
    def say_hi_class(cls):
        pass

    def run_self(self):
        self.x += 1
        print self.x # outputs 1
        self.say_hi()
        self.say_hi_static()
        self.say_hi_class()

    @staticmethod
    def run_static():
        print A.x  # outputs 0
        # A.say_hi() #  wrong
        A.say_hi_static()
        A.say_hi_class()

    @classmethod
    def run_class(cls):
        print cls.x # outputs 0
        # cls.say_hi() #  wrong
        cls.say_hi_static()
        cls.say_hi_class()

1 - we can directly call static and classmethods without initializing

# A.run_self() #  wrong
A.run_static()
A.run_class()

2- Static method cannot call self method but can call other static and classmethod

3- Static method belong to class and will not use object at all.

4- Class method are not bound to an object but to a class.

拿命拼未来 2024-07-13 08:14:16

Python 带有几个内置的装饰器。 其中最重要的三个是:

@classmethod
@staticmethod
@property

首先让我们注意,类的任何函数都可以通过此类的实例来调用(在我们初始化此类之后)。

@classmethod 是一种调用函数的方法,不仅作为类的实例,而且直接由类本身作为其第一个参数。

@staticmethod 是一种将函数放入类中的方法(因为它逻辑上属于该类),同时表明它不需要访问该类(因此我们不需要使用函数定义中的 self)。

让我们考虑以下类:

class DecoratorTest(object):

    def __init__(self):
        pass

    def doubler(self, x):
        return x*2

    @classmethod
    def class_doubler(cls, x): 
        """
        We need to use 'cls' instead of 'self'; 
        'cls' references the class instead of 
        an instance of the class
        """
        return x*2

    @staticmethod
    def static_doubler(x): 
        """
        No need to add 'self' here;
        static_doubler() could just be 
        a function outside the class.
        """
        return x*2

让我们看看它是如何工作的:

decor = DecoratorTest()

print(decor.doubler(5))
# 10

# a call with an instance of a class
print(decor.class_doubler(5)) 
# 10

# a direct call by the class itself
print(DecoratorTest.class_doubler(5)) 
# 10

# staticmethod can be called the same as classmethod.

# as an instance of the class
print(decor.static_doubler(5))
# 10

# or as a direct call 
print(DecoratorTest.static_doubler(5))
# 10

在这里您可以看到这些方法的一些用例。

额外奖励:您可以在此处阅读有关 @property 装饰器的信息

Python comes with several built-in decorators. The big three are:

@classmethod
@staticmethod
@property

First let's note that any function of a class can be called with instance of this class (after we initialized this class).

@classmethod is the way to call function not only as an instance of a class but also directly by the class itself as its first argument.

@staticmethod is a way of putting a function into a class (because it logically belongs there), while indicating that it does not require access to the class (so we don't need to use self in function definition).

Let's consider the following class:

class DecoratorTest(object):

    def __init__(self):
        pass

    def doubler(self, x):
        return x*2

    @classmethod
    def class_doubler(cls, x): 
        """
        We need to use 'cls' instead of 'self'; 
        'cls' references the class instead of 
        an instance of the class
        """
        return x*2

    @staticmethod
    def static_doubler(x): 
        """
        No need to add 'self' here;
        static_doubler() could just be 
        a function outside the class.
        """
        return x*2

Let's see how it works:

decor = DecoratorTest()

print(decor.doubler(5))
# 10

# a call with an instance of a class
print(decor.class_doubler(5)) 
# 10

# a direct call by the class itself
print(DecoratorTest.class_doubler(5)) 
# 10

# staticmethod can be called the same as classmethod.

# as an instance of the class
print(decor.static_doubler(5))
# 10

# or as a direct call 
print(DecoratorTest.static_doubler(5))
# 10

Here you can see some use cases for those methods.

Bonus: you can read about @property decorator here

葬﹪忆之殇 2024-07-13 08:14:16

@classmethod:可用于创建对该类创建的所有实例的共享全局访问......就像多个用户更新记录......
我特别发现它在创建单例时也很有用......:)

@static 方法:与关联的类或实例无关......但为了可读性可以使用静态方法

@classmethod : can be used to create a shared global access to all the instances created of that class..... like updating a record by multiple users....
I particulary found it use ful when creating singletons as well..:)

@static method: has nothing to do with the class or instance being associated with ...but for readability can use static method

梦在夏天 2024-07-13 08:14:16

类方法接收类作为隐式第一个参数,就像实例方法接收实例一样。 它是绑定到类而不是类的对象的方法。它可以访问类的状态,因为它采用指向类而不是对象实例的类参数。 它可以修改适用于该类的所有实例的类状态。 例如,它可以修改适用于所有实例的类变量。

另一方面,与类方法或实例方法相比,静态方法不接收隐式第一个参数。 并且无法访问或修改类状态。 它只属于类,因为从设计的角度来看这是正确的方法。 但就功能而言,在运行时并不绑定到类。

作为指导,使用静态方法作为实用程序,使用类方法(例如工厂)。 或者也许定义一个单例。 并使用实例方法对实例的状态和行为进行建模。

希望我说清楚了!

A class method receives the class as implicit first argument, just like an instance method receives the instance. It is a method which is bound to the class and not the object of the class.It has access to the state of the class as it takes a class parameter that points to the class and not the object instance. It can modify a class state that would apply across all the instances of the class. For example it can modify a class variable that will be applicable to all the instances.

On the other hand, a static method does not receive an implicit first argument, compared to class methods or instance methods. And can’t access or modify class state. It only belongs to the class because from design point of view that is the correct way. But in terms of functionality is not bound, at runtime, to the class.

as a guideline, use static methods as utilities, use class methods for example as factory . Or maybe to define a singleton. And use instance methods to model the state and behavior of instances.

Hope I was clear !

软甜啾 2024-07-13 08:14:16

我的贡献演示了 @classmethod@staticmethod 和实例方法之间的区别,包括实例如何间接调用 @staticmethod。 但是,与其从实例间接调用@staticmethod,不如将其设为私有可能更“Pythonic”。 这里没有演示从私有方法获取某些内容,但它基本上是相同的概念。

#!python3

from os import system
system('cls')
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

class DemoClass(object):
    # instance methods need a class instance and
    # can access the instance through 'self'
    def instance_method_1(self):
        return 'called from inside the instance_method_1()'

    def instance_method_2(self):
        # an instance outside the class indirectly calls the static_method
        return self.static_method() + ' via instance_method_2()'

    # class methods don't need a class instance, they can't access the
    # instance (self) but they have access to the class itself via 'cls'
    @classmethod
    def class_method(cls):
        return 'called from inside the class_method()'

    # static methods don't have access to 'cls' or 'self', they work like
    # regular functions but belong to the class' namespace
    @staticmethod
    def static_method():
        return 'called from inside the static_method()'
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''

# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()

# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''

# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''

# call class_method()
print(democlassObj.class_method() + '\n')
'''  called from inside the class_method() '''

# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''

"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""

My contribution demonstrates the difference amongst @classmethod, @staticmethod, and instance methods, including how an instance can indirectly call a @staticmethod. But instead of indirectly calling a @staticmethod from an instance, making it private may be more "pythonic." Getting something from a private method isn't demonstrated here but it's basically the same concept.

#!python3

from os import system
system('cls')
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

class DemoClass(object):
    # instance methods need a class instance and
    # can access the instance through 'self'
    def instance_method_1(self):
        return 'called from inside the instance_method_1()'

    def instance_method_2(self):
        # an instance outside the class indirectly calls the static_method
        return self.static_method() + ' via instance_method_2()'

    # class methods don't need a class instance, they can't access the
    # instance (self) but they have access to the class itself via 'cls'
    @classmethod
    def class_method(cls):
        return 'called from inside the class_method()'

    # static methods don't have access to 'cls' or 'self', they work like
    # regular functions but belong to the class' namespace
    @staticmethod
    def static_method():
        return 'called from inside the static_method()'
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''

# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()

# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''

# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''

# call class_method()
print(democlassObj.class_method() + '\n')
'''  called from inside the class_method() '''

# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''

"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""
我喜欢麦丽素 2024-07-13 08:14:16

您可能需要考虑以下之间的区别:

class A:
    def foo():  # no self parameter, no decorator
        pass

class B:
    @staticmethod
    def foo():  # no self parameter
        pass

python2 和 python3 之间发生了变化:

python2:

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

python3:

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

因此,对仅直接从类调用的方法使用 @staticmethod 在 python3 中已成为可选。 如果您想从类和实例中调用它们,您仍然需要使用 @staticmethod 装饰器。

unutbus 的回答已经很好地涵盖了其他情况。

You might want to consider the difference between:

class A:
    def foo():  # no self parameter, no decorator
        pass

and

class B:
    @staticmethod
    def foo():  # no self parameter
        pass

This has changed between python2 and python3:

python2:

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

python3:

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

So using @staticmethod for methods only called directly from the class has become optional in python3. If you want to call them from both class and instance, you still need to use the @staticmethod decorator.

The other cases have been well covered by unutbus answer.

偏爱你一生 2024-07-13 08:14:16

顾名思义,类方法用于更改类而不是对象。 要对类进行更改,他们将修改类属性(而不是对象属性),因为这就是更新类的方式。
这就是类方法将类(通常用“cls”表示)作为第一个参数的原因。

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

另一方面,静态方法用于执行未绑定到类的功能,即它们不会读取或写入类变量。 因此,静态方法不将类作为参数。 使用它们是为了使类可以执行与类的用途不直接相关的功能。

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."

Class methods, as the name suggests, are used to make changes to classes and not the objects. To make changes to classes, they will modify the class attributes(not object attributes), since that is how you update classes.
This is the reason that class methods take the class(conventionally denoted by 'cls') as the first argument.

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

Static methods on the other hand, are used to perform functionalities that are not bound to the class i.e. they will not read or write class variables. Hence, static methods do not take classes as arguments. They are used so that classes can perform functionalities that are not directly related to the purpose of the class.

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."
甜味拾荒者 2024-07-13 08:14:16

我认为给出 staticmethodclassmethod 的纯 Python 版本将有助于理解它们在语言级别上的差异(请参阅 描述符操作指南)。

它们都是非数据描述符(如果您熟悉 描述符)。

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner

I think giving a purely Python version of staticmethod and classmethod would help to understand the difference between them at language level (Refers to Descriptor Howto Guide).

Both of them are non-data descriptors (It would be easier to understand them if you are familiar with descriptors first).

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner
兮子 2024-07-13 08:14:16

从字面上分析@staticmethod,提供不同的见解。

类的普通方法是隐式动态方法,它将实例作为第一个参数。
相反,静态方法不将实例作为第一个参数,因此称为'static'

静态方法确实是一个普通的函数,与类定义之外的函数相同。
幸运的是,它被分组到类中,只是为了更接近它的应用位置,或者您可能会滚动鼠标来找到它。

Analyze @staticmethod literally providing different insights.

A normal method of a class is an implicit dynamic method which takes the instance as first argument.
In contrast, a staticmethod does not take the instance as first argument, so is called 'static'.

A staticmethod is indeed such a normal function the same as those outside a class definition.
It is luckily grouped into the class just in order to stand closer where it is applied, or you might scroll around to find it.

感情旳空白 2024-07-13 08:14:16

首先,让我们从一个示例代码开始,我们将使用它来理解这两个概念:

class Employee:

    NO_OF_EMPLOYEES = 0
  
    def __init__(self, first_name, last_name, salary):
        self.first_name = first_name
        self.last_name = last_name
        self.salary = salary
        self.increment_employees()

    def give_raise(self, amount):
        self.salary += amount

    @classmethod
    def employee_from_full_name(cls, full_name, salary):
        split_name = full_name.split(' ')
        first_name = split_name[0]
        last_name = split_name[1]
        return cls(first_name, last_name, salary)

    @classmethod
    def increment_employees(cls):
        cls.NO_OF_EMPLOYEES += 1

    @staticmethod
    def get_employee_legal_obligations_txt():
        legal_obligations = """
        1. An employee must complete 8 hours per working day
        2. ...
        """
        return legal_obligations

类方法

类方法接受类本身作为隐式参数,以及定义中指定的任何其他参数(可选)。 重要的是要理解类方法无法访问对象实例(就像实例方法一样)。 因此,类方法不能用于更改实例化对象的状态,但它们能够更改在该类的所有实例之间共享的类状态。
当我们需要访问类本身时,类方法通常很有用 - 例如,当我们想要创建工厂方法(即创建类实例的方法)时。 换句话说,类方法可以充当替代构造函数。

在我们的示例代码中,可以通过提供三个参数来构造 Employee 的实例; first_namelast_namesalary

employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.first_name)
print(employee_1.salary)

'Andrew'
85000

现在,我们假设可以在单个字段中提供员工姓名,其中名字和姓氏用空格分隔。 在这种情况下,我们可以使用名为 employee_from_full_name 的类方法,该方法总共接受三个参数。 第一个是类本身,它是一个隐式参数,这意味着在调用方法时不会提供它 - Python 会自动为我们执行此操作:

employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(employee_2.first_name)
print(employee_2.salary)

'John'
95000

请注意,也可以调用 employee_from_full_name 来自对象实例,尽管在这种情况下它没有多大意义:

employee_1 = Employee('Andrew', 'Brown', 85000)
employee_2 = employee_1.employee_from_full_name('John Black', 95000)

我们可能想要创建类方法的另一个原因是当我们需要更改类的状态时。 在我们的示例中,类变量 NO_OF_EMPLOYEES 跟踪当前为公司工作的员工人数。 每次创建 Employee 的新实例时都会调用此方法,并相应地更新计数:

employee_1 = Employee('Andrew', 'Brown', 85000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')
employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')

Number of employees: 1
Number of employees: 2

静态方法

另一方面,在静态方法中,实例(即 self )或者类本身(即cls)都作为隐式参数传递。 这意味着此类方法无法访问类本身或其实例。
现在有人可能会争辩说,静态方法在类的上下文中没有用,因为它们也可以放置在辅助模块中,而不是将它们添加为类的成员。 在面向对象编程中,将类构造为逻辑块非常重要,因此,当我们需要在类下添加方法时,静态方法非常有用,因为它在逻辑上属于该类。
在我们的示例中,名为 get_employee_legal_obligations_txt 的静态方法仅返回一个字符串,其中包含公司每个员工的法律义务。 此函数不与类本身或任何实例交互。 它可以被放置到不同的帮助器模块中,但是,它仅与此类相关,因此我们必须将其放置在 Employee 类下。

静态方法可以直接从类本身

print(Employee.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...

或类的实例访问:

employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...

引用

First let's start with an example code that we'll use to understand both concepts:

class Employee:

    NO_OF_EMPLOYEES = 0
  
    def __init__(self, first_name, last_name, salary):
        self.first_name = first_name
        self.last_name = last_name
        self.salary = salary
        self.increment_employees()

    def give_raise(self, amount):
        self.salary += amount

    @classmethod
    def employee_from_full_name(cls, full_name, salary):
        split_name = full_name.split(' ')
        first_name = split_name[0]
        last_name = split_name[1]
        return cls(first_name, last_name, salary)

    @classmethod
    def increment_employees(cls):
        cls.NO_OF_EMPLOYEES += 1

    @staticmethod
    def get_employee_legal_obligations_txt():
        legal_obligations = """
        1. An employee must complete 8 hours per working day
        2. ...
        """
        return legal_obligations

Class method

A class method accepts the class itself as an implicit argument and -optionally- any other arguments specified in the definition. It’s important to understand that a class method, does not have access to object instances (like instance methods do). Therefore, class methods cannot be used to alter the state of an instantiated object but instead, they are capable of changing the class state which is shared amongst all the instances of that class.
Class methods are typically useful when we need to access the class itself — for example, when we want to create a factory method, that is a method that creates instances of the class. In other words, class methods can serve as alternative constructors.

In our example code, an instance of Employee can be constructed by providing three arguments; first_name , last_name and salary.

employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.first_name)
print(employee_1.salary)

'Andrew'
85000

Now let’s assume that there’s a chance that the name of an Employee can be provided in a single field in which the first and last names are separated by a whitespace. In this case, we could possibly use our class method called employee_from_full_name that accepts three arguments in total. The first one, is the class itself, which is an implicit argument which means that it won’t be provided when calling the method — Python will automatically do this for us:

employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(employee_2.first_name)
print(employee_2.salary)

'John'
95000

Note that it is also possible to call employee_from_full_name from object instances although in this context it doesn’t make a lot of sense:

employee_1 = Employee('Andrew', 'Brown', 85000)
employee_2 = employee_1.employee_from_full_name('John Black', 95000)

Another reason why we might want to create a class method, is when we need to change the state of the class. In our example, the class variable NO_OF_EMPLOYEES keeps track of the number of employees currently working for the company. This method is called every time a new instance of Employee is created and it updates the count accordingly:

employee_1 = Employee('Andrew', 'Brown', 85000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')
employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')

Number of employees: 1
Number of employees: 2

Static methods

On the other hand, in static methods neither the instance (i.e. self) nor the class itself (i.e. cls) is passed as an implicit argument. This means that such methods, are not capable of accessing the class itself or its instances.
Now one could argue that static methods are not useful in the context of classes as they can also be placed in helper modules instead of adding them as members of the class. In object oriented programming, it is important to structure your classes into logical chunks and thus, static methods are quite useful when we need to add a method under a class simply because it logically belongs to the class.
In our example, the static method named get_employee_legal_obligations_txt simply returns a string that contains the legal obligations of every single employee of a company. This function, does not interact with the class itself nor with any instance. It could have been placed into a different helper module however, it is only relevant to this class and therefore we have to place it under the Employee class.

A static method can be access directly from the class itself

print(Employee.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...

or from an instance of the class:

employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...

References

别再吹冷风 2024-07-13 08:14:16

子类化时会出现一个非常重要的实际差异。 如果你不介意的话,我会劫持@unutbu的例子:

class A: 
    def foo(self, x): 
        print("executing foo(%s, %s)" % (self, x)) 
 
    @classmethod
    def class_foo(cls, x): 
        print("executing class_foo(%s, %s)" % (cls, x))
 
    @staticmethod 
    def static_foo(x): 
        print("executing static_foo(%s)" % x)

class B(A):
    pass

class_foo中,该方法知道它是在哪个类上调用的:

A.class_foo(1)
# => executing class_foo(<class '__main__.A'>, 1)
B.class_foo(1)
# => executing class_foo(<class '__main__.B'>, 1)

static_foo中,没有办法确定是在 A 还是 B 上调用:

A.static_foo(1)
# => executing static_foo(1)
B.static_foo(1)
# => executing static_foo(1)

请注意,这并不意味着您不能在 staticmethod 中使用其他方法,您可以只需直接引用该类,这意味着子类的静态方法仍将引用父类:

class A:
    @classmethod
    def class_qux(cls, x):
        print(f"executing class_qux({cls}, {x})")
    
    @classmethod
    def class_bar(cls, x):
        cls.class_qux(x)

    @staticmethod
    def static_bar(x):
        A.class_qux(x)

class B(A):
    pass

A.class_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)
B.class_bar(1)
# => executing class_qux(<class '__main__.B'>, 1)
A.static_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)
B.static_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)

One pretty important practical difference occurs when subclassing. If you don't mind, I'll hijack @unutbu's example:

class A: 
    def foo(self, x): 
        print("executing foo(%s, %s)" % (self, x)) 
 
    @classmethod
    def class_foo(cls, x): 
        print("executing class_foo(%s, %s)" % (cls, x))
 
    @staticmethod 
    def static_foo(x): 
        print("executing static_foo(%s)" % x)

class B(A):
    pass

In class_foo, the method knows which class it is called on:

A.class_foo(1)
# => executing class_foo(<class '__main__.A'>, 1)
B.class_foo(1)
# => executing class_foo(<class '__main__.B'>, 1)

In static_foo, there is no way to determine whether it is called on A or B:

A.static_foo(1)
# => executing static_foo(1)
B.static_foo(1)
# => executing static_foo(1)

Note that this doesn't mean you can't use other methods in a staticmethod, you just have to reference the class directly, which means subclasses' staticmethods will still reference the parent class:

class A:
    @classmethod
    def class_qux(cls, x):
        print(f"executing class_qux({cls}, {x})")
    
    @classmethod
    def class_bar(cls, x):
        cls.class_qux(x)

    @staticmethod
    def static_bar(x):
        A.class_qux(x)

class B(A):
    pass

A.class_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)
B.class_bar(1)
# => executing class_qux(<class '__main__.B'>, 1)
A.static_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)
B.static_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)
橘虞初梦 2024-07-13 08:14:16

太棒了;

staticmethod 本质上是绑定到类(及其实例)的函数。

classmethod 本质上是可继承的staticmethod

详情请参阅其他人的精彩回答。

tldr;

A staticmethod is essentially a function bound to a class (and consequently its instances)

A classmethod is essentially an inheritable staticmethod.

For details, see the excellent answers by others.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文