是什么之间的差异功能的装饰 @staticmethod 和一个装饰 @classmethod?

有帮助吗?

解决方案

也许一些示例代码会有所帮助:注意fooclass_foostatic_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(<class '__main__.A'>,1)

您也可以使用该课程致电A.foo(1)。事实上,如果你定义的东西是 一个类方法,可能是因为你打算从类而不是从类实例中调用它。 A.class_foo(1)会引发TypeError,但cls可以正常工作:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

人们在课程方法中发现的一个用途是创建可继承的替代构造函数


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

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

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

Staticmethods用于将与类有逻辑连接的函数分组到类中。


A只是一个函数,但是当你打电话给a.static_foo时,你不仅仅得到了这个函数, 你得到一个<!> quot;部分应用<!>将对象实例<=>绑定为函数的第一个参数的函数的版本。 <=>需要2个参数,而<=>只需要1个参数。

<=>绑定到<=>。这就是术语<!> quot; bound <!> quot;下面:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

使用<=>,<=>不受<=>约束,而<=>类绑定到<=>。

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

这里,使用static方法,即使它是一个方法,<=>只返回 一个好的'ole函数,没有参数限制。 <=>期待1个参数,和 <=>也要求1个参数。

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

当然,当您使用类<=>调用<=>时会发生同样的事情。

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

其他提示

staticmethod 是一种对调用它的类或实例一无所知的方法。它只是获取传递的参数,没有隐含的第一个参数。它在Python中基本没用 - 您只需使用模块函数而不是静态方法。

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

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

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

官方python文档:

@classmethod

  

类方法接收类为   隐含的第一个参数,就像一个   instance方法接收实例。   要声明一个类方法,请使用它   成语:

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

@classmethod表单是一个函数    decorator <!>#8211;看到的描述    功能中的函数定义   定义 了解详情。

     

它可以在课堂上调用   (例如C.f())或实例   (例如C().f())。实例是   被忽略了除了它的类。如果一个   为派生调用类方法   class,派生类对象是   作为暗示的第一个论点传递。

     

类方法与C ++不同   或Java静态方法。如果你想   那些,请参阅 staticmethod()   部分。

@staticmethod

  

静态方法没有收到   隐含第一个参数。宣布一个   静态方法,使用这个成语:

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

@staticmethod表单是一个函数    decorator <!>#8211;看到的描述    功能中的函数定义   定义 了解详情。

     

它可以在课堂上调用   (例如classmethod())或实例   (例如<=>)。实例是   忽略了它的类。

     

Python中的静态方法类似   那些在Java或C ++中找到的。为一个   更高级的概念,请参阅   本节中 <=>

这里是关于此的简短文章问题

  

@staticmethod函数只不过是在类中定义的函数。它可以在不首先实例化类的情况下调用。它<!>#8217; s定义通过继承是不可变的。

     

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

决定是否使用 @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
  

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来加入另一个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.maketrans,从Python 3中的string模块移动。它使转换表适合str.translate使用。从字符串的实例中使用它似乎相当愚蠢,如下所示,但是从dict.fromkeys模块导入函数是相当笨拙的,并且能够从类中调用它是很好的,如在classmethod

# 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'

类方法

类方法类似于实例方法,因为它采用隐式的第一个参数,但不是取实例,而是采用类。通常这些用作替代构造函数以获得更好的语义用法,并且它将支持继承。

内置类方法的最典型示例是staticmethod。它被用作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)
<class '__main__.MyDict'>

请参阅其他类似的 pandas源代码替代构造函数的示例,另请参阅有关 <=> 的官方Python文档,以及 <=>

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

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

我们假设我们有一个Person类,它接受两个参数first_namelast_name并创建@classmethod的实例。

class Person(object):

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

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

但是,您可以使用<=>实现相同的目标,如下所述

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

静态方法:这很简单,它没有绑定到实例或类,您可以使用类名称来调用它。

因此,在上面的示例中,您需要验证<=>不应超过20个字符,您可以简单地执行此操作。

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

您只需使用<=>

进行调用即可
Person.validate_name("Gaurang Shah")

在Python 2.4中添加了@decorators如果你正在使用python <!> lt; 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方法成为类方法的另一个好处是,子类可以决定更改它的实现,可能因为它非常通用并且可以处理多种类型的集群,所以只需检查类的名称就可以了还不够。

我认为更好的问题是<!>“;你什么时候使用@classmethod vs @staticmethod?<!>;

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

@staticmethod提供了边际性能提升,但我还没有看到一个类中的静态方法的有效使用,这是在类之外无法实现的独立函数。

静态的方法:

  • 简单的功能没有自的论点。
  • 工作的类属性;不实例属性。
  • 可以通过两种类和实例。
  • 该建立在功能staticmethod()用于创建它们。

惠的静态方法:

  • 它本地化的函数名在classscope
  • 它的动作功能码接近它在哪里使用
  • 更方便的进口与模块级别的功能,因为每一种方法并没有要专门口

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

类方法:

  • 职能,第一个参数作为classname。
  • 可以通过两种类和实例。
  • 这些都是创建classmethod在建造的功能。

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

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

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

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

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

明确的指导如何使用静态的,类或抽象的方法在蟒蛇 是一个很好的链接为这个主题,并概述如下。

@staticmethod 功能是没有什么比一个功能的定义内一类。它是不可调用的实例,类第一次。它的定义是不可改变的通过继承。

  • 蟒蛇不必化束缚方法的对象。
  • 它简化的可读性代码的,它不取决于国家的对象本身;

@classmethod 功能也不可调用的实例,类,但是其定义如下分类,不是父类,通过继承,可以复盖亚类。这是因为第一个参数 @classmethod 职能必须始终是 cls (类)。

  • 工厂的方法, 那是用来创建一个实例一类的例如使用某种预处理。
  • 静态的方法,呼吁静态的方法:如果分裂一个静态的方法在几个静态的方法,你不应该硬代码类的名字,但使用类方法

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

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

差异: 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',)

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

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

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

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

这有效,但请注意,现在子类(Foo2)中的magic()实现无法再利用该类的特定内容。例如,假设Foo2.magic()有一个名为Foo的方法,要在classmethod In Foo2 MAGIC的<=>实现中使用:

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" 

此处的解决方法是在<=>中调用<=>,但随后您将重复自己(如果<=>的名称发生更改,则必须记住更新该<=>方法)。

对我而言,这略微违反了开放/封闭原则,因为在<=>中做出的决定会影响您在派生类中重构公共代码的能力(即它不太适合扩展)。如果<=>是<=>我们就没事了:

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()

给予:<=>

我将尝试使用示例解释基本区别。

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方法但可以调用其他静态和classmethod

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

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

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

@static方法:与关联的类或实例无关......但为了便于阅读,可以使用静态方法

我的贡献证明了@classmethod@staticmethod和实例方法之间的区别,包括实例如何间接调用<=>。但是,不是间接地从实例中调用<=>,而是将其设为私有,可能更多<!>“pythonic。<!>”;从私有方法中获取某些东西并没有在这里展示,但它基本上是相同的概念。

#!python3

from os import system
system('cls')
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

class DemoClass(object):
    # instance methods need a class instance and
    # can access the instance through 'self'
    def instance_method_1(self):
        return 'called from inside the instance_method_1()'

    def instance_method_2(self):
        # an instance outside the class indirectly calls the static_method
        return self.static_method() + ' via instance_method_2()'

    # class methods don't need a class instance, they can't access the
    # instance (self) but they have access to the class itself via 'cls'
    @classmethod
    def class_method(cls):
        return 'called from inside the class_method()'

    # static methods don't have access to 'cls' or 'self', they work like
    # regular functions but belong to the class' namespace
    @staticmethod
    def static_method():
        return 'called from inside the static_method()'
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''

# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %   %

# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()

# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''

# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''

# call class_method()
print(democlassObj.class_method() + '\n')
'''  called from inside the class_method() '''

# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''

"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""

类名方法,类方法用于更改类而不是对象。要对类进行更改,它们将修改类属性(而不是对象属性),因为这是更新类的方式。 这就是类方法将类(通常用'cls'表示)作为第一个参数的原因。

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

另一方面,静态方法用于执行未绑定到类的功能,即它们不会读取或写入类变量。因此,静态方法不会将类作为参数。它们被使用,以便类可以执行与类的目的无直接关系的功能。

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."

您可能需要考虑以下区别:

Class A:
    def foo():  # no self parameter, no decorator
        pass

Class B:
    @staticmethod
    def foo():  # no self parameter
        pass

python2和python3:

之间发生了变化

python2:

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

python3:

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()

所以使用@staticmethod只能直接从类调用的方法在python3中变成了可选项。如果你想从类和实例中调用它们,你仍然需要使用<=>装饰器。

其他案例已得到了unutbus答案的充分报道。

分析@staticmethod 字面,提供不同的见解。

类的常规方法是隐式动态方法,它将实例作为第一个参数。
相反,static方法不会将实例作为第一个参数,因此称为'static'

静态方法确实是一个与类定义之外的函数相同的正常函数 幸运的是,它只是为了在应用它的地方站得更近,或者你可以滚动来找到它。

短的回答。第一个参数:

  • 正常的方法:第一个参数是目前的对象
  • 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 类的静态的方法)
class Point
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def frompolar(cls, radius, angle):
        """The `cls` argument is the `Point` class itself"""
        return cls(radius * cos(angle), radius * sin(angle))

    @staticmethod
    def angle(x, y):
        return atan(y, x)


p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)

angle = Point.angle(3, 2)

在iPython中快速查看其他相同的方法会发现@staticmethod会产生边际性能提升(以纳秒为单位),但除此之外它似乎没有任何功能。此外,在编译期间通过staticmethod()处理方法的额外工作(在运行脚本时执行任何代码之前发生)可能会消除任何性能提升。

为了代码可读性,我要避免使用<=>,除非你的方法用于纳秒数的工作量。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top