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

我在使用 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)

After reading many helpful posts here, I figured how I could add @staticmethod above to get the code working. I am a python newbie. Can someone please explain why one would want to define static methods? Or, why are not all methods defined as static methods?

61908 次浏览

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

Python 的站点在这里有一些关于静态方法的文档:
Http://docs.python.org/library/functions.html#staticmethod

静态方法在 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

为什么要定义静态方法

假设我们有一个称为 Mathclass

nobody will want to create object of class Math
然后调用类似于 ceilfloor以及 fabs的方法。 < br >

所以我们把它们变成 static

例如做

>> Math.floor(3.14)

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

所以它们在某种程度上是有用的,你不需要创建一个类的实例来使用它们。

Why are not all methods defined as static methods?

他们不能访问实例变量。

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

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

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

当您在对象实例上调用 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)

Static methods have limited use, because they don't have access to the attributes of an instance of a class (like a regular method does), and they don't have access to the attributes of the class itself (like a class method does).

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

然而,它们可以有用地将一些实用函数与一个类组合在一起——例如一个简单的从一种类型到另一种类型的转换——这个类不需要访问除了提供的参数之外的任何信息(也许还需要访问模块的一些全局属性)

它们可以放在类之外,但是将它们分组到类中可能有意义,因为它们只适用于那里。

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

这并不是你真正想问的问题,但是既然你说你是一个蟒蛇新手,也许这会有所帮助,而且没有其他人站出来明确地说出来。

我永远不会通过使该方法成为静态方法来修复上述代码。我可能会放弃这门课,只写一个函数:

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 的一个优点是,它不会强迫您为所有事情使用类。只有在有应该与方法关联的数据或状态时才能使用它们,而这正是类的用途。否则,您可以使用函数,这就是函数的用途。

详细说明见 这篇文章

DR

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

它减少了内存使用,因为 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.它允许方法重写,因为如果方法是在模块级别(即在类之外)定义的,那么子类就不能重写该方法。

因为名称空间函数很好(如前所述) :

  1. 当我想要明确说明不改变对象状态的方法时,我会使用静态方法。这阻碍了我团队中的人员开始在这些方法中更改对象的属性。

  2. 当我重构非常糟糕的代码时,我首先尝试创建尽可能多的方法 @staticmethod。这样我就可以将这些方法提取到一个类中——虽然我同意,我很少使用这种方法,但它确实有几次很有帮助。

据我估计,使用 @staticmethod与仅仅在类之外定义函数并将其与类分离相比,没有任何一个 表演的好处。

我认为唯一能证明他们存在的理由就是方便。静态方法在其他流行的编程语言中很常见,那么为什么不使用 python 呢?如果你想创建一个行为与你所创建的类密切相关的函数,但是它并没有实际访问/修改该类实例的内部数据,而是将其概念化为该类的一个典型方法,那么在它上面添加一个 @staticmethod,任何阅读你的代码的人都会立即学到很多关于该方法的性质及其与该类的关系的知识。

One thing I occasionally like to do is place functionality that my class uses internally a lot into private @staticmethods. That way I do not clutter the API exposed by my module with methods that no one using my module would ever need to see let alone use.

The alternatives to a staticmethod are: classmethod, instancemethod, and function. If you don't know what these are, scroll down to the last section. If a staticmethod is better than any of these alternatives, depends on for what purpose it is written.

Python 静态方法的优点

  • 如果不需要访问类或实例的属性或方法,staticmethod优于 classmethodinstancemethod。通过这种方式(从 @staticmethod装饰器)可以清楚地看到类和实例的状态没有被读取或修改。然而,使用 function可以使这种区别更加明显(见缺点)。
  • staticmethod的呼叫签名与 classmethodinstancemethod(即 <instance>.<method>(<arguments>))的呼叫签名相同。因此,如果以后或在派生类中需要,可以很容易地用 之一替换它。你不能用一个简单的 function做到这一点。
  • 可以使用 staticmethod代替 function来表明它主观上属于一个类,并防止名称空间冲突。

Python 静态方法的缺点

  • 它不能访问实例或类的属性或方法。
  • staticmethod的呼叫签名与 classmethodinstancemethod的呼叫签名相同。这掩盖了一个事实,即 staticmethod实际上并不读取或修改任何对象信息。这使得代码更难阅读。为什么不用 function呢?
  • 如果需要从定义 staticmethod的类/实例之外调用它,则很难重用 staticmethod。如果有任何重用的潜力,function是更好的选择。
  • The staticmethod is seldom used, so people reading code that includes one may take a little longer to read it.

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