我在代码
的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)
在这里阅读了很多有用的帖子后,我想到了如何在上面添加@staticmethod以使代码正常工作。我是python新手。有人可以解释为什么人们想要定义静态方法吗?或者,为什么并非所有方法都定义为静态方法?
答案 0 :(得分:146)
有关详细说明,请参阅this article。
<强> TL; DR 强>
1.它消除了self
参数的使用。
2.它减少了内存使用量,因为Python不必为每个被发现的对象实例化bound-method:
>>>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 :(得分:95)
静态方法的用途有限,因为它们无法访问类实例的属性(就像常规方法那样),并且它们无法访问类本身的属性(如类方法确实如此。
所以它们对日常方法没用。
然而,它们可以用于将一些效用函数与一个类组合在一起 - 例如,从一种类型到另一种类型的简单转换 - 除了提供的参数之外不需要访问任何信息(可能还有一些属于模块的全局属性。)
它们可以放在课堂之外,但是在课堂上将它们分组可能在它们仅在那里适用的地方有意义。
您还可以通过实例或类引用该方法,而不是模块名称,这可以帮助读者了解该方法的相关实例。
答案 2 :(得分:16)
这不是你的实际问题,但是因为你说你是一个蟒蛇新手也许它会有所帮助,没有其他人出来并明确说出来。
我永远不会通过使该方法成为静态方法来修复上述代码。我要么已经抛弃了这个类,只是编写了一个函数:
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的一个优点是它不会强迫你为所有东西使用类。只有当存在应该与方法关联的数据或状态时,才可以使用它们,这是类的用途。否则你可以使用函数,这是函数的用途。
答案 3 :(得分:12)
为什么要定义静态方法?
假设我们有一个名为class
的{{1}},那么
没有人会想要创建Math
的对象
然后在其上调用class Math
和ceil
以及floor
等方法。
所以我们制作fabs
。
例如做
static
比
好多了>> Math.floor(3.14)
所以它们在某种程度上是有用的。您无需创建类的实例即可使用它们。
为什么并非所有方法都定义为静态方法?
他们无权访问实例变量。
>> mymath = Math()
>> mymath.floor(3.14)
这就是为什么我们不将所有方法都设为静态。
答案 4 :(得分: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)
答案 5 :(得分:4)
静态方法很棒,因为您不必声明方法所属对象的实例。
python的网站上有一些关于静态方法的优秀文档:
http://docs.python.org/library/functions.html#staticmethod
答案 6 :(得分:3)
staticmethod
的替代项是:classmethod
,instancemethod
和function
。如果您不知道这些是什么,请向下滚动到最后一部分。如果staticmethod
优于上述任何一种选择,则取决于它是出于什么目的编写的。
staticmethod
比classmethod
或instancemethod
更好。这样,很明显(从@staticmethod
装饰器可以看出,没有读取或修改类和实例的状态。但是,使用function
可以使区分更加清楚(请参见缺点)。staticmethod
的呼叫签名与classmethod
或instancemethod
(即<instance>.<method>(<arguments>)
)的呼叫签名相同。因此,如果以后在派生类中或派生类中需要使用三个之一,可以轻松地替换它。简单的function
不能做到这一点。staticmethod
代替function
,以明确表明它主观上属于一个类并防止命名空间冲突。staticmethod
的呼叫签名与classmethod
或instancemethod
的呼叫签名相同。这掩盖了staticmethod
实际上并未读取或修改任何对象信息的事实。这使代码更难阅读。为什么不只使用function
?staticmethod
很难重用,如果您需要从定义它的类/实例外部调用它的话。如果有重用的可能,则function
是更好的选择。staticmethod
很少使用,因此人们在阅读包含其中一个代码的代码时可能会花费更长的时间。要讨论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
答案 7 :(得分:1)
因为命名空间函数很好(如前所述):
当我想明确关于不改变对象状态的方法时,我使用静态方法。这使我团队中的人不鼓励在这些方法中更改对象的属性。
当我重构真正糟糕的代码时,我首先尝试尽可能多地创建方法@staticmethod
。这使我可以将这些方法提取到一个类中 - 尽管我同意,这很少我使用它,它确实有用了几次。
答案 8 :(得分: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
答案 9 :(得分:0)
在我的估计中,使用@staticmethod
没有单一的性能好处,而只是在类之外定义函数并与类别分开,否则它将是@staticmethod
的。
我唯一要说的就是为了方便他们存在。静态方法在其他流行的编程语言中很常见,为什么不用python呢?如果要创建一个函数,其行为与您正在为其创建的类非常紧密地关联,但它实际上不会以证明将其概念化为典型的方式访问/修改类的实例的内部数据然后该类的方法在它上面打一个@staticmethod
,任何阅读你代码的人都会立即学到很多关于该方法的性质及其与该类的关系的信息。
我偶尔喜欢做的一件事是将我的班级内部使用的功能放到私人@staticmethod
中。这样我就不会混淆我的模块暴露的API,使用我的模块的任何人都不需要看到更不用说的方法。