unu*_*tbu 2969

也许一些示例代码会有所帮助:注意调用签名的区别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()
Run Code Online (Sandbox Code Playgroud)

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

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)
Run Code Online (Sandbox Code Playgroud)

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

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Run Code Online (Sandbox Code Playgroud)

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

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Run Code Online (Sandbox Code Playgroud)

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


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

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

A.static_foo('hi')
# executing static_foo(hi)
Run Code Online (Sandbox Code Playgroud)

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


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

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

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
Run Code Online (Sandbox Code Playgroud)

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

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
Run Code Online (Sandbox Code Playgroud)

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

print(a.static_foo)
# <function static_foo at 0xb7d479cc>
Run Code Online (Sandbox Code Playgroud)

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

print(A.static_foo)
# <function static_foo at 0xb7d479cc>
Run Code Online (Sandbox Code Playgroud)

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

Tho*_*ers 772

一个静态方法是一无所知,它被称为上类或实例的方法.它只是获取传递的参数,没有隐含的第一个参数.它在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
>>> 
Run Code Online (Sandbox Code Playgroud)

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

Ter*_*son 138

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


Chr*_* B. 99

官方python文档:

@classmethod

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

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 
Run Code Online (Sandbox Code Playgroud)

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

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

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

@staticmethod

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

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 
Run Code Online (Sandbox Code Playgroud)

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

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

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


Tom*_*and 71

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

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

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

  • 不.使用静态方法你根本不受约束; 没有隐含的第一个参数.通过使用classmethod,您可以获得调用方法的类(如果直接在类上调用它)的隐式第一个参数,或者调用方法的实例的类(如果在实例上调用它). (7认同)
  • 可以扩展一下来表明,通过将类作为第一个参数,类方法可以直接访问其他类属性和方法,而静态方法则不能(它们需要对MyClass.attr进行硬编码) (6认同)
  • 那么这是否意味着通过使用静态方法,我总是绑定到父类,而通过类方法,我绑定了我在其中声明类方法的类(在这种情况下是子类)? (2认同)
  • “它的定义通过继承是不可变的。” 在Python中没有任何意义,你可以覆盖静态方法就可以了。 (2认同)

Du *_* D. 62

要决定是否使用@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
Run Code Online (Sandbox Code Playgroud)

  • 即使代码放在不同的类中,或者类名发生更改,“cls._counter”仍然是“cls._counter”。`Apple._counter` 是特定于 `Apple` 类的;对于不同的类,或者当类名更改时,您需要更改引用的类。 (2认同)

Aar*_*all 48

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

正常实例方法

首先我要解释一下a_normal_instance_method.这恰恰称为" 实例方法 ".当使用实例方法时,它被用作部分函数(与在源代码中查看时为所有值定义的总函数相对),即,当使用时,第一个参数被预定义为实例.对象,具有所有给定的属性.它具有绑定到它的对象的实例,并且必须从对象的实例调用它.通常,它将访问实例的各种属性.

例如,这是一个字符串的实例:

', '
Run Code Online (Sandbox Code Playgroud)

如果我们join在这个字符串上使用instance方法来连接另一个iterable,那么它显然是实例的一个函数,除了是可迭代列表的函数之外['a', 'b', 'c']:

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
Run Code Online (Sandbox Code Playgroud)

绑定方法

可以通过点查找绑定实例方法以供稍后使用.

例如,这会将str.join方法绑定到':'实例:

>>> join_with_colons = ':'.join 
Run Code Online (Sandbox Code Playgroud)

之后我们可以将它用作已经绑定了第一个参数的函数.这样,它就像实例上的部分函数一样:

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'
Run Code Online (Sandbox Code Playgroud)

静态方法

静态方法并没有把实例作为参数.

它与模块级功能非常相似.

但是,模块级功能必须存在于模块中并专门导入到使用它的其他位置.

但是,如果它附加到对象,它也将通过导入和继承方便地跟随对象.

静态方法的一个示例是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}
Run Code Online (Sandbox Code Playgroud)

在python 2中,您必须从越来越不实用的字符串模块中导入此函数:

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
Run Code Online (Sandbox Code Playgroud)

类方法

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

内置类方法的最典型示例是dict.fromkeys.它被用作dict的替代构造函数(非常适合当你知道你的键是什么并且想要它们的默认值时.)

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
Run Code Online (Sandbox Code Playgroud)

当我们继承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'>
Run Code Online (Sandbox Code Playgroud)

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


Gau*_*hah 37

我开始用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
Run Code Online (Sandbox Code Playgroud)

现在,如果需要只使用一个名称创建一个类,只需要一个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
Run Code Online (Sandbox Code Playgroud)

但是,你可以使用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, "")
Run Code Online (Sandbox Code Playgroud)

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

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

@staticmethod  
def validate_name(name):
    return len(name) <= 20
Run Code Online (Sandbox Code Playgroud)

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

Person.validate_name("Gaurang Shah")
Run Code Online (Sandbox Code Playgroud)

  • 这是一篇旧文章,但要实现接受一个或两个参数的构造函数,更Pythonic的方法是使用“def __init__(self,first_name,last_name="")”而不是类方法“get_person”。在这种情况下,结果也将完全相同。 (7认同)

Jen*_*man 30

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

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

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


Nat*_*lus 29

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

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

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


Lax*_*xmi 27

静态方法:

  • 简单的函数,没有自我论证.
  • 处理类属性; 不是实例属性.
  • 可以通过类和实例调用.
  • 内置函数staticmethod()用于创建它们.

静态方法的好处:

  • 它在classscope中本地化函数名称
  • 它将功能代码移动到更接近使用位置的位置
  • 导入和模块级函数更方便,因为不必专门导入每种方法

    @staticmethod
    def some_static_method(*args, **kwds):
        pass
    
    Run Code Online (Sandbox Code Playgroud)

分类方法:

  • 具有第一个参数作为类名的函数.
  • 可以通过类和实例调用.
  • 这些是使用classmethod内置函数创建的.

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass
    
    Run Code Online (Sandbox Code Playgroud)


Arm*_*her 21

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

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

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>
Run Code Online (Sandbox Code Playgroud)

  • 使用元类有什么好处? (9认同)

zan*_*ngw 19

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

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

  • Python不必实例化对象的绑定方法.
  • 它简化了代码的可读性,并且它不依赖于对象本身的状态;

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

  • 工厂方法,用于为类创建实例,例如使用某种预处理.
  • 调用静态方法的静态方法:如果在多个静态方法中拆分静态方法,则不应对类名进行硬编码,而应使用类方法


Sel*_*lva 15

让我先说一下用@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',)
Run Code Online (Sandbox Code Playgroud)


Ada*_*kin 12

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

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"
Run Code Online (Sandbox Code Playgroud)

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

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
Run Code Online (Sandbox Code Playgroud)

这有效,但请注意,现在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" 
Run Code Online (Sandbox Code Playgroud)

这里的解决办法是打电话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()
Run Code Online (Sandbox Code Playgroud)

得到: In Foo2 MAGIC


ill*_*ato 11

Python 带有几个内置的装饰器。三巨头是:

@classmethod
@staticmethod
@property
Run Code Online (Sandbox Code Playgroud)

首先我们要注意,类的任何函数都可以使用此类的实例来调用(在我们初始化此类之后)。

@classmethod不仅可以作为类的实例来调用函数,还可以直接将类本身作为其第一个参数来调用。

@staticmethod是一种将函数放入类中的方法(因为它逻辑上属于该类),同时表明它不需要访问该类(因此我们不需要self在函数定义中使用)。

让我们考虑下面的类:

class DecoratorTest(object):

    def __init__(self):
        pass

    def doubler(self, x):
        return x*2

    @classmethod
    def class_doubler(cls, x): 
        """
        We need to use 'cls' instead of 'self'; 
        'cls' references the class instead of 
        an instance of the class
        """
        return x*2

    @staticmethod
    def static_doubler(x): 
        """
        No need to add 'self' here;
        static_doubler() could just be 
        a function outside the class.
        """
        return x*2
Run Code Online (Sandbox Code Playgroud)

让我们看看它是如何工作的:

decor = DecoratorTest()

print(decor.doubler(5))
# 10

# a call with an instance of a class
print(decor.class_doubler(5)) 
# 10

# a direct call by the class itself
print(DecoratorTest.class_doubler(5)) 
# 10

# staticmethod can be called the same as classmethod.

# as an instance of the class
print(decor.static_doubler(5))
# 10

# or as a direct call 
print(DecoratorTest.static_doubler(5))
# 10
Run Code Online (Sandbox Code Playgroud)

在这里您可以看到这些方法的一些用例。

奖励:你可以在这里阅读有关@property装饰器的内容


blu*_*ote 10

第一个参数不同

  • 普通方法:第一个参数是(自动)当前对象
  • classmethod:第一个参数是(自动)当前对象的类
  • staticmethod:第一个参数不会自动传递

更详细地...

普通方法

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

def f(self, x, y)
Run Code Online (Sandbox Code Playgroud)

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

类方法

装饰方法时

@classmethod
def f(cls, x, y)
Run Code Online (Sandbox Code Playgroud)

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

静态方法

装饰方法时

@staticmethod
def f(x, y)
Run Code Online (Sandbox Code Playgroud)

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

用法

  • classmethod 主要用于替代构造函数。
  • staticmethod不使用对象的状态。它可能是类外部的函数。它仅放在类中以对具有相似功能的函数进行分组(例如,类似于Java的Math类静态方法)
def f(self, x, y)
Run Code Online (Sandbox Code Playgroud)


Riz*_*taz 8

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

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

1 - 我们可以直接调用static和classmethods而无需初始化

# A.run_self() #  wrong
A.run_static()
A.run_class()
Run Code Online (Sandbox Code Playgroud)

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

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

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


Dav*_*han 7

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

class A:
    def foo():  # no self parameter, no decorator
        pass
Run Code Online (Sandbox Code Playgroud)

class B:
    @staticmethod
    def foo():  # no self parameter
        pass
Run Code Online (Sandbox Code Playgroud)

这在 python2 和 python3 之间发生了变化:

蟒蛇2:

>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
Run Code Online (Sandbox Code Playgroud)

蟒蛇3:

>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
Run Code Online (Sandbox Code Playgroud)

因此@staticmethod,在 python3 中使用 仅直接从类调用的方法已成为可选。如果你想从类和实例中调用它们,你仍然需要使用@staticmethod装饰器。

unutbus answer已经很好地涵盖了其他情况。


小智 7

类方法接收类作为隐式第一个参数,就像实例方法接收实例一样。它是一个绑定到类而不是类的对象的方法。它可以访问类的状态,因为它需要一个指向类而不是对象实例的类参数。它可以修改将应用于类的所有实例的类状态。例如,它可以修改适用于所有实例的类变量。

另一方面,与类方法或实例方法相比,静态方法不会接收隐式第一个参数。并且无法访问或修改类状态。它只属于类,因为从设计的角度来看这是正确的方法。但在功能方面,在运行时,并没有绑定到类。

作为准则,使用静态方法作为实用程序,使用类方法,例如作为 factory 。或者也许定义一个单身人士。并使用实例方法对实例的状态和行为进行建模。

希望我很清楚!


H.H*_*H.H 7

当有继承时就会出现差异。

假设有两个类——Parent 和 Child。如果要使用@staticmethod,print_name 方法应该写两次,因为类的名称应该写在打印行中。

class Parent:
   _class_name = "Parent"

   @staticmethod
   def print_name():
       print(Parent._class_name)


class Child(Parent):
   _class_name = "Child"

   @staticmethod
   def print_name():
       print(Child._class_name)


Parent.print_name()
Child.print_name()
Run Code Online (Sandbox Code Playgroud)

但是,对于@classmethod,不需要写两次print_name 方法。

class Parent:
    _class_name = "Parent"

    @classmethod
    def print_name(cls):
        print(cls._class_name)


class Child(Parent):
    _class_name = "Child"


Parent.print_name()
Child.print_name()
Run Code Online (Sandbox Code Playgroud)


vij*_*jay 6

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

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


Mic*_*rtz 5

我的贡献演示之间的差异@classmethod@staticmethod以及实例方法,包括如何实例可以间接调用@staticmethod。但是不是@staticmethod从实例间接调用 a ,而是将其设为私有可能更“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)
'''
"""
Run Code Online (Sandbox Code Playgroud)


Mil*_*vić 5

实例方法

+ 可以修改对象实例状态

+ 可以修改类状态

类方法

- 无法修改对象实例状态

+ 可以修改类状态

静态方法

- 无法修改对象实例状态

- 无法修改类状态

class MyClass:
    ''' 
    Instance method has a mandatory first attribute self which represent the instance itself. 
    Instance method must be called by a instantiated instance.
    '''
    def method(self):
        return 'instance method called', self
    
    '''
    Class method has a mandatory first attribute cls which represent the class itself. 
    Class method can be called by an instance or by the class directly. 
    Its most common using scenario is to define a factory method.
    '''
    @classmethod
    def class_method(cls):
        return 'class method called', cls
    
    '''
    Static method doesn’t have any attributes of instances or the class. 
    It also can be called by an instance or by the class directly. 
    Its most common using scenario is to define some helper or utility functions which are closely relative to the class.
    '''
    @staticmethod
    def static_method():
        return 'static method called'


obj = MyClass()
print(obj.method())
print(obj.class_method()) # MyClass.class_method()
print(obj.static_method()) # MyClass.static_method()
Run Code Online (Sandbox Code Playgroud)

输出:

('instance method called', <__main__.MyClass object at 0x100fb3940>)
('class method called', <class '__main__.MyClass'>)
static method called
Run Code Online (Sandbox Code Playgroud)

我们实际上可以访问对象 instance 的实例方法,所以这是我的类对象的一个​​实例,而使用类方法我们可以访问类本身。但不是任何对象,因为类方法并不真正关心对象的存在。但是,您可以在对象实例上调用类方法和静态方法。这会起作用,它并没有真正的区别,所以当您再次调用静态方法时,它会起作用,并且会知道您要调用哪个方法。

静态方法用于执行一些实用任务,类方法用于工厂方法。工厂方法可以为不同的用例返回类对象。

最后,为了更好地理解,举一个简短的例子:

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

    @classmethod
    def get_from_string(cls, name_string: str):
        first_name, last_name = name_string.split()
        if Student.validate_name(first_name) and Student.validate_name(last_name):
            return cls(first_name, last_name)
        else:
            print('Invalid Names')

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


stackoverflow_student = Student.get_from_string('Name Surname')
print(stackoverflow_student.first_name) # Name
print(stackoverflow_student.last_name) # Surname
Run Code Online (Sandbox Code Playgroud)