在Python中使用静态方法有什么好处?

Cur*_*arn 73 python

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

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)
Run Code Online (Sandbox Code Playgroud)

在这里阅读了很多有用的帖子之后,我想到了如何在上面添加@staticmethod以使代码正常工作.我是python新手.有人可以解释为什么人们想要定义静态方法吗?或者,为什么并非所有方法都定义为静态方法?

zan*_*etu 164

有关详细说明,请参阅此文章.

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
Run Code Online (Sandbox Code Playgroud)

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

4.它允许方法覆盖,如果方法是在模块级定义的(即在类外),则子类将无法覆盖该方法.

  • 这应该是公认的答案。任何实例上的静态方法和类本身都是同一个对象这一事实是一个真正的优势,尤其是当您有很多实例时(例如,每个实例都用于可变数据库记录)。 (4认同)
  • 3. - 如果没有状态,那么为什么首先要创建一个类?模块功能同样好,而且代码更少。 (3认同)
  • 这应该是投票最多的答案!谢谢! (2认同)
  • +1 并同意@ZhuoyunWei。唯一的答案解释了为什么静态方法有时比类方法更可取的几个原因(尽管 1 和 3 实际上是相同的原因)。 (2认同)
  • “为什么静态方法”的最佳答案,但原始问题还问“为什么不是所有方法都是静态的?”。简短的“无法访问实例属性”也涵盖了这一点。 (2认同)

Odd*_*ing 102

静态方法的使用有限,因为它们无法访问类实例的属性(就像常规方法那样),并且它们无法访问类本身的属性(就像类方法一样) ).

因此它们对日常方法没有用.

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

它们可以被放在课堂之外,但是将它们分组到课堂中可能是有意义的,它们只适用于那里.

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

  • @ Curious2learn:不是*every*,但*some*方法作为静态方法很有用.想想一个示例`Locale`类,其实例将是locales(duh).`getAvailableLocales()`方法将是这种类的静态方法的一个很好的例子:它明显属于Locale类,但显然也不属于任何特定实例. (5认同)
  • Guido 的一句话有助于决定何时使用静态方法(从不):“我们都知道静态方法有多么有限。(它们基本上是一个意外 - 回到 Python 2.2 时代,当时我正在发明新式类和描述符,我本想实现类方法,但一开始我不理解它们,不小心先实现了静态方法。然后为时已晚,删除它们并只提供类方法。” (2认同)

Vic*_*ler 19

这不是你的实际问题,但是因为你说你是一个蟒蛇新手也许它会有所帮助,而且没有其他人能够明确地说出来.

我永远不会通过使该方法成为静态方法来修复上述代码.我要么抛弃了这个类,只是写了一个函数:

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

Choices=range(100)
print drawSample(5,Choices)
Run Code Online (Sandbox Code Playgroud)

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

import sample

Choices=range(100)
print sample.drawSample(5,Choices)
Run Code Online (Sandbox Code Playgroud)

或者我会在类中添加一个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)
Run Code Online (Sandbox Code Playgroud)

(我还更改了上例中的案例约定,以匹配PEP 8推荐的样式.)

Python的一个优点是它不会强迫你为所有东西使用类.只有当存在应该与方法关联的数据或状态时,才可以使用它们,这是类的用途.否则你可以使用函数,这是函数的用途.

  • +1:对于OP的一些误解,这是一个很好的解释.并且你非常诚实地说,你没有*实际上回答他关于静态方法的问题,但你宁愿给出一个更好的*解决方案*说他的问题根本不需要课程. (3认同)

Pra*_*are 16

为什么要定义静态方法

假设我们有一个class叫做的Math

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

所以我们制作它们static.

例如做

>> Math.floor(3.14)
Run Code Online (Sandbox Code Playgroud)

好多了

>> mymath = Math()
>> mymath.floor(3.14)
Run Code Online (Sandbox Code Playgroud)

所以它们在某种程度上是有用的.您无需创建类的实例即可使用它们.

为什么并非所有方法都定义为静态方法

他们无权访问实例变量.

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
Run Code Online (Sandbox Code Playgroud)

这就是为什么我们不将所有方法都设为静态的原因.

  • 但为什么不包数学呢?Python有这样的包,你不需要_need_类定义来创建命名空间. (7认同)
  • @extraneon:是的,我知道,但是我想要一些简单而熟悉的解释,所以我使用了`Math`.这就是为什么我把"M"大写了. (6认同)
  • OP没有问什么是静态方法.他问他们有什么好处.您正在解释如何使用它们,而不是它们如何有用.在您的特定示例中,命名空间会更有意义. (6认同)
  • -1:良好和正确的解释,但是一个非常糟糕的选择例子:首先没有理由让你的'Math`成为一个类,一个模块会更合适.尝试找一个有意义的类作为一个类的例子,而不是那个"没有人想要创建"*的对象. (4认同)
  • 并且*然后*给出一个合法的用例的例子,用于*one*(或*some*)类的方法是静态的,但不是全部*.如果类的方法的*all*都是静态的,那么class应该是一个模块.如果*none*是静态的,那么你没有回答这个问题. (3认同)

Mat*_*son 12

当您从对象实例调用函数对象时,它将变为"绑定方法"并获取实例对象本身作为第一个参数传入.

当您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)
Run Code Online (Sandbox Code Playgroud)

  • +1:最后一个关于静态方法*和*类方法的一个很好的解释.虽然你没有解释*为什么*人们会想要使用静态方法,但至少你在一个简单的例子中清楚地解释了两者*都比官方文档好得多. (3认同)

Joo*_*eey 10

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

Python静态方法的优点

  • 如果您不需要访问类或实例的属性或方法,astaticmethod比 aclassmethod或 好instancemethod。这样很明显(从@staticmethod装饰器)类和实例的状态没有被读取或修改。但是,使用 afunction会使这种区别更加清晰(请参阅缺点)。
  • a 的调用签名与staticmethodaclassmethod或的调用签名相同instancemethod,即<instance>.<method>(<arguments>)。因此,如果稍后或在派生类中需要,可以很容易地将其替换为三者之一。你不能用一个简单的function.
  • 一个staticmethod可以用来代替function,以明确其主观上属于一类,并防止命名空间冲突。

Python静态方法的缺点

  • 它不能访问实例或类的属性或方法。
  • a 的调用签名staticmethod与 aclassmethod或的调用签名相同instancemethod。这掩盖了实际上staticmethod不读取或修改任何对象信息的事实。这使得代码更难阅读。为什么不直接使用function?
  • staticmethod如果您需要从定义它的类/实例外部调用它,则很难重用A。如果有任何重复使用的潜力,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
Run Code Online (Sandbox Code Playgroud)