当前位置:  开发笔记 > 编程语言 > 正文

@staticmethod和@classmethod有什么区别?

如何解决《@staticmethod和@classmethod有什么区别?》经验,为你挑选了18个好方法。

装饰的功能@staticmethod和装饰的功能有什么区别@classmethod



1> unutbu..:

也许一些示例代码会有所帮助:注意调用签名的区别foo,class_foo并且static_foo:

class A(object):
    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    

a = A()

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

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

对于classmethods,对象实例的类隐式传递为第一个参数而不是self.

a.class_foo(1)
# executing class_foo(,1)

您也可以class_foo使用该课程进行呼叫.实际上,如果你将某些东西定义为类方法,那可能是因为你打算从类而不是类实例中调用它.A.foo(1)会产生一个TypeError,但A.class_foo(1)工作得很好:

A.class_foo(1)
# executing class_foo(,1)

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


使用staticmethods时,self(对象实例)和cls(类)都不会 作为第一个参数隐式传递.它们的行为类似于普通函数,除了您可以从实例或类中调用它们:

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

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

Staticmethods用于将与类具有某种逻辑连接的函数分组到类中.


foo只是一个函数,但是当你调用时a.foo不仅仅是获取函数,你得到函数的"部分应用"版本,并将对象实例a绑定为函数的第一个参数.foo期望2个参数,而a.foo只需要1个参数.

a必然会foo.这就是下面"绑定"一词的含义:

print(a.foo)
# >

a.class_foo,a不是必然的class_foo,而是类A必然class_foo.

print(a.class_foo)
# >

在这里,使用static方法,即使它是一个方法,a.static_foo只返回一个没有参数绑定的良好'ole函数.static_foo期望1个参数,并且也 a.static_foo期望1个参数.

print(a.static_foo)
# 

当然,当您static_foo与班级打电话时会发生同样的事情A.

print(A.static_foo)
# 


@Alcott:您可能希望将函数移动到类中,因为它在逻辑上属于该类.在Python源代码(例如multiprocessing,turtle,dist-packages)中,它用于从模块命名空间"隐藏"单下划线"私有"函数.然而,它的使用高度集中在几个模块中 - 可能表明它主要是一种风格的东西.虽然我找不到任何这样的例子,但`@ staticmethod`可能有助于通过子类覆盖来组织代码.没有它,你就会在模块名称空间中浮动函数的变体.
我不明白使用staticmethod的问题是什么.我们可以使用一个简单的外部函数.
@Alcott:正如unutbu所说,静态方法是一种组织/风格特征.有时一个模块有很多类,一些辅助函数在逻辑上与给定的类相关联而不与其他类相关联,因此不使用许多"自由函数""污染"模块是有意义的,并且最好使用静态方法,而不是依赖于混合类和函数的糟糕风格defs一起代码只是为了表明它们是"相关的"
...以及***和*why*使用实例,类或静态方法的一些解释.你没有说一句,但OP也没有问过这个问题.
还有一个用于`@ staticmethod`的东西 - 你可以用它去除残骸.我在Python中实现一种编程语言 - 库定义的函数使用静态的`execute`方法,其中用户定义的函数需要实例参数(即函数体).此装饰器消除了PyCharm检查器中的"未使用的参数自我"警告.
我特别喜欢这个答案最后一条分界线之后的部分-我从未意识到`a.foo`会返回本质上是一个咖喱函数,这就是当它说出<bound method ...>时的含义。
@Dogweather:[classmethod的主要用途之一是定义"替代构造函数"](http://stackoverflow.com/a/1950927/190597)
可能值得补充的另一件事是`A.foo`意味着什么,因为你已经彻底解释了其他5个案例(`a.foo`,`a.class_foo`,`a.static_foo`,`A.class_foo `和`A.static_foo`):一个"未绑定的方法"(2.x)或一个普通的函数(3.x),它期望一个`A`实例作为它的第一个参数.

2> Thomas Woute..:

一个静态方法是一无所知,它被称为上类或实例的方法.它只是获取传递的参数,没有隐含的第一个参数.它在Python中基本没用 - 您可以使用模块函数而不是静态方法.

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

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


静态方法并非无用 - 它是一种将函数放入类中的方法(因为它在逻辑上属于那里),同时表明它不需要访问类.
因此,只是"基本上"无用.这种组织以及依赖注入是static方法的有效用法,但由于模块(而不是Java中的类)是Python中代码组织的基本元素,因此它们的使用和实用性很少.
也许是为了继承缘故?静态方法可以像实例方法和类方法一样继承和覆盖,并且查找按预期工作(与Java不同).无论是在类还是实例上调用,静态方法都不是静态解析的,因此类和静态方法之间的唯一区别是隐式的第一个参数.
它们还创建了一个更清晰的命名空间,并且更容易理解该函数与该类有关.
在类中如何与类或其实例无关时,定义类中的方法有什么逻辑?
-1:这个答案A)给出了类方法的一个非常重要的特性作为其实用程序的解释(因此它们仅在子类化时才有用,允许你使用子类的名称,*真的*?),并且B)暗示"静态方法应该是模块方法",虽然它们在语义上是,但如果你的模块定义了许多类,并且给定的辅助函数仅适用于给定的类*,则使用它们会产生*很多*或有意义*.所以非常糟糕的回答有很多误解.
@BenJames:静态方法应该与它定义的类有关,它不需要类或实例数据来完成它的工作.(见http://stackoverflow.com/questions/7855237)
所以哪个更好:使用sin,cos等方法获得Math __class__,或者使用带有函数sin,cos等的Math __module__等.在我看来后者会更好,所以我很难想到静态方法有用的可能情况.我认为Helper方法是一种潜在的情况,但如果一个帮助程序如此通用以至于不需要来自类或类实例的任何东西,那么你真的不得不怀疑它是否会更好地作为库中的实用程序例程.
Classmethods不是为了'允许你使用子类的名字',它们是你可以知道*调用方法的类*.它们为您提供了类*对象*,而不是名称.事实上,这就是他们的全部目的.
当你有一个类实例时,它通常更容易调用`inst.method()`而不是`module.method()`.有时你甚至不知道你正在使用哪个模块,毕竟Python _is_是一种动态语言......
-1也是我在评论中的原因.我发现静态方法至少与存在基于继承的查找时的类方法一样有用,如@haridsv所述.请参见http://stackoverflow.com/questions/5060172/can-staticmethods-be-inherited.在实现模板方法设计模式时,我更喜欢静态方法而不是类方法,因为static方法的参数较小.
实际上,静态方法并非无用,从方法访问的角度来看,如果你只是将它作为模块的一部分,它就没有区别.但是想象一下,你可能有这样的情况,你有一个包含几个类的模块,静态方法可能只是逻辑上属于父模块以外的一个类.@haridsv静态方法不能被覆盖,这适用于Java和Python,它们可以被继承但不能被覆盖.
@MestreLion:我同意你的看法.我不确定为什么这个答案如此受欢迎.它真的很差,并且有一些误解.

3> Terence Simp..:

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



4> Chris B...:

官方python文档:

@classmethod

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

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

@classmethod形式是一个函数 装饰 -见的功能定义描述函数定义的细节.

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

类方法与C++或Java静态方法不同.如果您需要,请参阅staticmethod()本节.

@staticmethod

静态方法不会接收隐式的第一个参数.要声明静态方法,请使用此惯用法:

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

@staticmethod形式是一个函数 装饰 -见的功能定义描述函数定义的细节.

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

Python中的静态方法与Java或C++中的静态方法类似.有关更高级的概念,请参阅 classmethod()本节.



5> Tom Neyland..:

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

@staticmethod函数只不过是在类中定义的函数.它可以在不首先实例化类的情况下调用.它的定义是通过继承不可变的.

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


不.使用静态方法你根本不受约束; 没有隐含的第一个参数.通过使用classmethod,您可以获得调用方法的类(如果直接在类上调用它)的隐式第一个参数,或者调用方法的实例的类(如果在实例上调用它).
可以扩展一下来表明,通过将类作为第一个参数,类方法可以直接访问其他类属性和方法,而静态方法则不能(它们需要对MyClass.attr进行硬编码)

6> Du D...:

要决定是否使用@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 other class,
        #       you don't have to rename the class reference 

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

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



7> Aaron Hall..:

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在这个字符串上使用instance方法来连接另一个iterable,那么它显然是实例的一个函数,除了是可迭代列表的函数之外['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.maketransstringPython 3中的模块移动.它使转换表适合于使用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)

有关替代构造函数的其他类似示例,请参阅pandas源代码,另请参阅有关classmethod和的官方Python文档staticmethod.



8> Gaurang Shah..:

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

类方法: Python与Java不同,C++没有构造函数重载.所以要实现这一点,你可以使用classmethod.下面的例子将解释这一点

让我们考虑,我们有一个Person类,它有两个参数first_namelast_name和创建人的实例.

class Person(object):

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

现在,如果需要只使用一个名称创建一个类,只需要一个Person,你就不能在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

但是,你可以使用first_name下面提到的相同的东西

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, "")

静态方法::这很简单,它没有绑定到实例或类,您只需使用类名称调用它.

因此,在上面的示例中,您需要一个@classmethod不超过20个字符的验证,您可以简单地执行此操作.

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

你可以简单地使用Class Name调用

Person.validate_name("Gaurang Shah")



9> Jens Timmerm..:

在Python 2.4中添加了@decorators如果您使用的是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)

还要注意这是使用classmethod和静态方法的一个很好的例子.静态方法显然属于类,因为它在内部使用类Cluster.classmethod只需要有关类的信息,而不需要对象的实例.

制作的另一个好处_is_cluster_for方法一类方法是这样子类可以决定改变它的实现,也许是因为它是非常通用的,可以处理多种类型的集群,所以只检查类的名称是不够的.



10> Nathan Tregi..:

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

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

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



11> Laxmi..:

静态方法:

简单的函数,没有自我论证.

处理类属性; 不是实例属性.

可以通过类和实例调用.

内置函数staticmethod()用于创建它们.

静态方法的好处:

它在classscope中本地化函数名称

它将功能代码移动到更接近使用位置的位置

导入和模块级函数更方便,因为不必专门导入每种方法

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

分类方法:

具有第一个参数作为类名的函数.

可以通过类和实例调用.

这些是使用classmethod内置函数创建的.

 @classmethod
 def some_class_method(cls, *args, **kwds):
     pass



12> Armin Ronach..:

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

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)

>>> classmethod(f).__get__(None, C)
>

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

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


使用元类有什么好处?

13> zangw..:

关于如何在Python中使用静态,类或抽象方法的权威指南是本主题的一个很好的链接,并总结如下.

@staticmethod函数只不过是在类中定义的函数.它可以在不首先实例化类的情况下调用.它的定义是通过继承不可变的.

Python不必实例化对象的绑定方法.

它简化了代码的可读性,并且它不依赖于对象本身的状态;

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

工厂方法,用于为类创建实例,例如使用某种预处理.

调用静态方法的静态方法:如果在多个静态方法中拆分静态方法,则不应对类名进行硬编码,而应使用类方法



14> Selva..:

让我先说一下用@classmethod和@staticmethod修饰的方法之间的相似性.

相似性:它们都可以在本身上调用,而不仅仅是类的实例.因此,它们在某种意义上都是Class的方法.

差异:类方法将接收类本身作为第一个参数,而静态方法则不接受.

因此,静态方法在某种意义上并不局限于类本身,只是因为它可能具有相关功能而挂在那里.

>>> 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',)



15> Adam Parkin..:

关于staticmethod vs classmethod的另一个考虑因素是继承.假设您有以下课程:

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

然后你想要bar()在子类中重写:

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

这有效,但请注意,现在bar()子类(Foo2)中的实现无法再利用该类特定的任何内容.例如,假设Foo2有一个名为magic()你想要在Foo2执行中使用的方法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" 

这里的解决办法是打电话Foo2.magic()bar(),但此时你重复自己(如果名称Foo2的改变,你必须记住要更新bar()方法).

对我来说,这是对开放/封闭原则的轻微违反,因为做出的决定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



16> blue_note..:

第一个参数不同

普通方法:第一个参数是(自动)当前对象

classmethod:第一个参数是(自动)当前对象的类

staticmethod:第一个参数不会自动传递

更详细地...

普通方法

调用对象的方法时,它会自动获得一个额外的参数self作为其第一个参数。即方法

def f(self, x, y)

必须使用2个参数调用。self是自动传递的,它是对象本身

类方法

装饰方法时

@classmethod
def f(cls, x, y)

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

静态方法

装饰方法时

@staticmethod
def f(x, y)

该方法根本没有任何自动参数。仅提供调用它的参数。

用法

classmethod 主要用于替代构造函数。

staticmethod不使用对象的状态。它可能是类外部的函数。它仅放在类中以对具有相似功能的函数进行分组(例如,类似于Java的Math类静态方法)

def f(self, x, y)



17> Rizwan Mumta..:

我将尝试使用示例来解释基本差异.

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 - 我们可以直接调用static和classmethods而无需初始化

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

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

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

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



18> vijay..:

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

@static方法:与与...相关联的类或实例无关,但出于可读性考虑,可以使用static方法

推荐阅读
小色米虫_524
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有