在Python中使用静态方法的优点是什么?


89

我在代码中遇到了python中的未绑定方法错误

import random

class Sample(object):
'''This class defines various methods related to the sample'''

    def drawSample(samplesize,List):
        sample=random.sample(List,samplesize)
        return sample

Choices=range(100)
print Sample.drawSample(5,Choices)

在阅读了许多有用的文章之后,我想到了如何在@staticmethod上面添加内容以使代码正常工作。我是python新手。有人可以解释一下为什么要定义静态方法吗?还是为什么不将所有方法都定义为静态方法?


1
这是一个奇怪的问题。静态方法是设计的必要条件。这不是“优势”。使用它们是因为必须这样做。具有静态方法是类的设计功能。您是在问什么首先要使用静态方法吗?我认为可以将问题改写为更清楚地定义您需要了解的内容。
S.Lott

15
不,我不想知道它们是什么。我想知道的是为什么它是一种“必要性”,这一点从其他人的回答中可以清楚地看出来。那是您何时定义它,而不是非静态方法。谢谢。
Curious2learn 2010年

3
@ S.Lott:什么时候需要使用静态方法而不是使用普通的类方法?据我所知,类方法可以完成staticmethod可以做的所有事情。STATICMETHOD确实有“后发优势”在这篇文章中列出的其他地方,但我可以“看不到,为什么不能在可用于静态方法的任何地方使用的类方法的任何理由,因此使其成为一种必然。
RFV

Answers:


126

静态方法的使用受到限制,因为它们无法访问类的实例的属性(就像常规方法一样),并且它们也不能访问类本身的属性(就像类方法一样) )。

因此,它们对于日常方法没有用。

但是,它们对于将某些实用程序功能与一个类组合在一起很有用-例如,从一种类型到另一种类型的简单转换-除了提供的参数(可能还有模块全局的某些属性)之外,不需要访问任何信息。 )

可以将它们放在班级之外,但是将它们分组在班级内可能在仅适用于此的地方才有意义。

您还可以通过实例或类而不是模块名称来引用该方法,这可以帮助读者了解该方法与哪个实例相关。


8
@ Curious2learn:并非每种方法,但有些方法可用作静态方法。考虑一个示例Locale类,其实例将是语言环境(duh)。一个getAvailableLocales()方法是这样的类的静态方法的一个很好的例子:它显然是属于Locale类,同时也明确不属于任何特定实例。
MestreLion'5

...也不是类方法,因为它可能不需要访问任何类的方法。
MestreLion'5

编辑者指出,静态方法可以通过显式地从class_name.attributecls.attribute或而不是导航到类属性self.attribute。对于“公共”属性,这是正确的。按照惯例,您不应以这种方式访问​​带有下划线隐藏的属性或由两个下划线修饰的名称。这也意味着,当属性在继承层次结构上转移位置时,您的代码将更加脆弱。
Oddthinking

Guido的一句话帮助决定何时使用静态方法(从不):“我们都知道静态方法的局限性。(它们基本上是偶然的-早在Python 2.2天内,我就发明了新型类和描述符,我原本打算实现类方法,但起初我不了解它们,而首先偶然地实现了静态方法。然后将它们删除而仅提供类方法为时已晚。”
Boris Churzin

187

请参阅本文以获取详细说明。

TL; DR

1.它消除了使用self参数。

2.它减少了内存使用,因为Python不必为每个实例化的对象实例化绑定方法

>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True

3.它提高了代码的可读性,表明该方法不依赖于对象本身的状态。

4.它允许方法重写,因为如果方法是在模块级别(即,在类外部)定义的,则子类将无法重写该方法。


3
这应该是公认的答案。任何实例上的静态方法和类本身都是同一对象的事实是一个真正的优势,尤其是当您有很多实例(例如,每个实例用于可变数据库记录)时。
卓卓云

+1并同意@ZhuoyunWei。只有答案可以解释为什么静态方法有时比类方法更可取的几个原因(尽管1和3实际上是相同的原因)。
亚历克斯

1
最佳答案是“为什么要使用静态方法”,但最初的问题还问“为什么所有方法都不都是静态的?”。简短的“无权访问实例属性”将对此进行介绍。
阿旭

IMO的唯一真正优势是您可以在子类中重写它,但是即使那样,您仍会感觉到您在OOP方面做错了什么,您将在哪种用例中这样做?
鲍里斯·楚津

23

这并不是您实际问题的重点,但是由于您已经说过自己是python新手,所以也许会有所帮助,而且没有其他人明确表示出来。

我永远不会通过将方法设为静态方法来修复上述代码。我要么放弃了该类,而只是编写了一个函数:

def drawSample(samplesize,List):
    sample=random.sample(List,samplesize)
    return sample

Choices=range(100)
print drawSample(5,Choices)

如果您有许多相关功能,则可以将它们分组在一个模块中-例如,将它们全部放在同一个文件中,sample.py例如命名;然后

import sample

Choices=range(100)
print sample.drawSample(5,Choices)

或者,我将向__init__类添加一个方法并创建一个具有有用方法的实例:

class Sample(object):
'''This class defines various methods related to the sample'''

    def __init__(self, thelist):
        self.list = thelist

    def draw_sample(self, samplesize):
        sample=random.sample(self.list,samplesize)
        return sample

choices=Sample(range(100))
print choices.draw_sample(5)

(我还更改了上面示例中的大小写约定,以匹配PEP 8建议的样式。)

Python的优点之一是它不会强迫您对所有内容使用类。仅当存在与方法相关联的数据或状态时,才可以使用它们,这就是类的用途。否则,您可以使用函数,这就是函数的作用。


感谢您的评论。在这种情况下,我确实需要一个类,因为我想使用绘制的样本。不,我没有使用静态方法,而是想学习,因为我在查找有关错误消息的信息时遇到了这个术语。但是您关于在不定义类的情况下将功能收集到模块中的建议对于我需要的其他功能会有所帮助。那谢谢啦。
Curious2learn 2010年

4
+1:对于OP的一些误解,这是一个很好的解释。坦率地说,您实际上并没有真正回答他关于静态方法的问题,但是您提供了一个更好的解决方案,说他的问题根本不需要类。
MestreLion'5

22

为什么要定义静态方法

假设我们有一个class叫做Math然后

没有人会希望创建的对象class Math
,然后调用类似的方法ceil,并floorfabs它。

所以我们做它们static

例如做

>> Math.floor(3.14)

>> mymath = Math()
>> mymath.floor(3.14)

因此,它们在某种程度上很有用。您无需创建类的实例即可使用它们。

为什么不将所有方法都定义为静态方法

他们无权访问实例变量。

class Foo(object):
    def __init__(self):
        self.bar = 'bar'

    def too(self):
        print self.bar

    @staticmethod
    def foo():
        print self.bar

Foo().too() # works
Foo.foo() # doesn't work

这就是为什么我们不使所有方法都是静态的。


10
但是为什么不打包数学呢?Python为此提供了软件包,您无需类定义即可创建名称空间。
Extraneon 2010年

6
@extraneon:是的,我知道,但是我想要一些简单而熟悉的解释,所以我使用了Math。这就是为什么我大写M
Pratik Deoghare 2010年

6
OP没有问什么是静态方法。他问他们有什么优势。您在解释如何使用它们,而不是它们如何有用。在您的特定示例中,名称空间会更有意义。
哈维尔2010年

4
-1:正确且正确的解释,但示例选择得很差:没有理由让您Math首先成为一门课,一个模块会更合适。尝试找到一个对一个类有意义的示例,而不是“没有人会创建对象的对象”的示例。
MestreLion'5

3
随后给出一个合法的用例的例如一个(或一些)的类的方法是静态的,但不是全部。如果所有类的方法都是静态的,则class应该是一个模块。如果没有一个是静态的,那么您将无法回答问题。
MestreLion'5

13

当从对象实例调用函数对象时,它成为“绑定方法”,并获取实例对象本身作为第一个参数传递。

当您classmethod在对象实例上调用对象(包装功能对象)时,实例对象的类将作为第一个参数传入。

调用staticmethod对象(包装功能对象)时,不使用任何隐式第一个参数。

class Foo(object):

    def bar(*args):
        print args

    @classmethod
    def baaz(*args):
        print args

    @staticmethod
    def quux(*args):
        print args

>>> foo = Foo()

>>> Foo.bar(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)

>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)

3
+1:最后很好地解释了什么是静态方法类方法。虽然你没有解释为什么人会想用一个静态方法,至少你清楚在一个简单的例子解释了两者低于官方的文档做要好得多。
MestreLion'5

3

静态方法非常有用,因为您不必声明该方法所属的对象的实例。

python的站点在此处提供了一些有关静态方法的出色文档:http :
//docs.python.org/library/functions.html#staticmethod


谢谢大卫。但是为什么不将每个方法都定义为静态方法呢,因为它们也适用于实例。这样做有什么弊端吗?
Curious2learn 2010年

4
@ Curious2learn:否,对于静态方法,您无权访问该实例:该实例除其类外
Felix Kling

4
该论点在Java中是正确的,在Java中,函数不能自己生存,而总是在类的上下文中定义。但是在Python中,您可以具有函数和静态类函数。这个答案并没有真正表明为什么选择静态方法代替不在类中的方法。
Extraneon 2010年

1
@extraneon-更多的是代码组织偏好设置;使用静态方法可以提供一种额外的选择。
查尔斯·达菲

@Felix-谢谢。这阐明了为什么每个方法都不应该是静态方法的原因。
Curious2learn 2010年

3

一个替代方案staticmethod是:classmethodinstancemethod,和function。如果您不知道这些是什么,请向下滚动到最后一部分。如果astaticmethod优于这些替代方法,则取决于它是出于什么目的编写的。

Python静态方法的优点

  • 如果您不需要访问类或实例的属性或方法,则astaticmethod优于aclassmethodinstancemethod。这样,从@staticmethod装饰器可以清楚地看到,类和实例的状态没有被读取或修改。但是,使用afunction可以使这种区分更加清晰(请参见缺点)。
  • 的呼叫签名staticmethod是相同的classmethodinstancemethod,即<instance>.<method>(<arguments>)。因此,如果以后在派生类中或派生类中需要它,可以很容易地用三个之一替换它。您不能通过简单的操作function
  • staticmethod可以使用A代替afunction来明确说明它在主观上属于一个类并防止名称空间冲突。

Python静态方法的缺点

  • 它无法访问实例或类的属性或方法。
  • a的呼叫签名staticmethod与aclassmethod或的呼叫签名相同instancemethod。这掩盖了实际上staticmethod并没有读取或修改任何对象信息的事实。这使代码更难阅读。为什么不只是使用function
  • staticmethod,如果你在任何时候需要从类/实例,其中它被定义之外的电话就很难再使用。如果有重复使用的潜力,afunction是更好的选择。
  • staticmethod应用较少,所以人们阅读的代码,其中包括一个可能需要一点时间来阅读。

Python中静态方法的替代方法

为了讨论的优势staticmethod,我们需要知道替代品是什么以及它们之间的区别。

  • staticmethod属于一类,但不能访问或修改任何实例或类的信息。

有三种替代方法:

  • classmethod访问调用者的类。
  • instancemethod访问调用者的实例和它的类。
  • function无关带班。它的功能最接近staticmethod

这是代码中的样子:

# function
# has nothing to do with a class
def make_cat_noise(asker_name):
    print('Hi %s, mieets mieets!' % asker_name)

# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey')  # just a function

class Cat:
    number_of_legs = 4

    # special instance method __init__
    def __init__(self, name):
        self.name = name

    # instancemethod
    # the instance (e.g. Cat('Kitty')) is passed as the first method argument
    def tell_me_about_this_animal(self, asker_name):
        print('Hi %s, This cat has %d legs and is called %s'
              % (asker_name, self.number_of_legs, self.name))

    # classmethod
    # the class (e.g. Cat) is passed as the first method argument
    # by convention we call that argument cls
    @classmethod
    def tell_me_about_cats(cls, asker_name):
        print("Hi %s, cats have %d legs."
              % (asker_name, cls.number_of_legs))
        # cls.name  # AttributeError because only the instance has .name
        # self.name  # NameError because self isn't defined in this namespace

    # staticmethod
    # no information about the class or the instance is passed to the method
    @staticmethod
    def make_noise(asker_name):
        print('Hi %s, meooow!' % asker_name)
        # class and instance are not accessible from here

# one more time for fun!
make_cat_noise('JOey')  # just a function

# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey')  # staticmethod
Cat.tell_me_about_cats('JOey')  # classmethod
# Cat.tell_me_about_this_animal('JOey')  # instancemethod -> TypeError

# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty')  # mycat is an instance of the class Cat
mycat.make_noise('JOey')  # staticmethod
mycat.tell_me_about_cats('JOey')  # classmethod
mycat.tell_me_about_this_animal('JOey')  # instancemethod

1

因为命名空间功能很好(如前所述):

  1. 当我想明确说明不更改对象状态的方法时,我使用静态方法。这不鼓励我们团队中的人们开始在那些方法中更改对象的属性。

  2. 当我重构非常烂的代码时,我首先尝试制作尽可能多的方法@staticmethod。然后,这使我可以将这些方法提取到类中-尽管我同意,但我很少使用它,但确实有帮助。


1

根据我的估计,与仅将函数定义在类之外并与之分开的功能相比,使用s并没有单一的性能优势。@staticmethod@staticmethod

我要说的唯一证明其存在的理由就是便利。静态方法在其他流行的编程语言中很常见,那么为什么不使用python?如果要创建一个行为与创建该类的行为密切相关的函数,但实际上并不能以证明将其概念化为典型值的方式访问/修改该类实例的内部数据该类的方法然后@staticmethod在其上拍打一个,任何阅读您的代码的人都将立即了解该方法的性质及其与该类的关系。

我偶尔喜欢做的一件事是将类在内部大量使用的功能放入private @staticmethod。这样,我就不会使用任何模块都不会使我的模块公开的API变得混乱,更不用说使用它了。


0

静态方法几乎没有使用Python的理由。您可以使用实例方法或类方法。

def method(self, args):
    self.member = something

@classmethod
def method(cls, args):
    cls.member = something

@staticmethod
def method(args):
    MyClass.member = something
    # The above isn't really working
    # if you have a subclass

你说“差不多”。有没有比其他选择更好的地方?
哈维尔2010年

@Javier:我想不出一种,但可能只有一种,为什么要将该方法包含在Python库中呢?
GeorgSchölly10年

1
@ Javier,@ Georg:您坚信Python语料库没有内容。
查尔斯·梅里亚姆

-1:这个答案不存在任何的使用情况staticmethod任何一个什么样的解释classmethod是为什么,以及如何比静态的“更好”。
MestreLion'5

@CharlesMerriam:当然,静态方法也有使用,否则在Python 3中(大多数遗留的东西都被删除了)将被丢弃或弃用。没有一个单一的对字staticmethod的文档来支持你的要求,这是多余的内容或乔治的说法,即classmethod应改为使用)。
MestreLion'5
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.