Python staticmethod和classmethod的区别

Python staticmethod和classmethod的区别,python,oop,methods,python-decorators,Python,Oop,Methods,Python Decorators,用修饰的函数和用修饰的函数有什么区别?astaticmethod是一种对调用它的类或实例一无所知的方法。它只获取传递的参数,没有隐式的第一个参数。它在Python中基本上是无用的——您可以只使用模块函数而不是staticmethod class Apple: _counter = 0 @staticmethod def about_apple(): print('Apple is good for you.') # note you

用修饰的函数和用修饰的函数有什么区别?

astaticmethod是一种对调用它的类或实例一无所知的方法。它只获取传递的参数,没有隐式的第一个参数。它在Python中基本上是无用的——您可以只使用模块函数而不是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
另一方面,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
没有任何隐式参数。

@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'>>
这是一篇关于这个问题的短文


@staticmethod函数只不过是类内部定义的函数。它不需要先实例化类就可以调用。它的定义通过继承是不可变的

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


也许一些示例代码会有所帮助:注意
foo
class\u-foo
static\u-foo
的调用签名的差异:

class A(object):
    def foo(self, x):
        print(f"executing foo({self}, {x})")

    @classmethod
    def class_foo(cls, x):
        print(f"executing class_foo({cls}, {x})")

    @staticmethod
    def static_foo(x):
        print(f"executing static_foo({x})")

a = A()
下面是对象实例调用方法的常用方式。对象实例
a
,作为第一个参数隐式传递

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)
class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m
您还可以使用类调用
class\u foo
。事实上,如果你把某件事定义为 一个类方法,可能是因为您打算从类而不是从类实例调用它
A.foo(1)
会引发一个类型错误,但是
A.class\u foo(1)
工作正常:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)
Staticmethods用于将与类具有某种逻辑连接的函数分组到类

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."

foo
只是一个函数,但是当您调用
a.foo
时,您不仅得到了函数, 将对象实例
a
绑定为函数的第一个参数,得到函数的“部分应用”版本
foo
需要2个参数,而
a.foo
只需要1个参数

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)
class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m
a
绑定到
foo
。这就是下文“受约束”一词的含义:

这里,对于staticmethod,即使它是一个方法,
a.static\u foo
只返回 一个好的ole函数,没有参数绑定<代码>静态_foo需要1个参数,并且
a.static\u foo
也需要1个参数

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

官方python文档:


类方法接收类作为 隐式的第一个参数,就像 实例方法接收实例。 要声明类方法,请使用以下命令 成语:

@classmethod
表单是一个函数 –请参见以下内容的说明: 有关详细信息,请参阅中的函数定义

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

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>, 1)
class A(object):
    m=54

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

类方法不同于C++ 或者Java静态方法。如果你愿意 那些,看看这个 节

静态方法不接收 隐式第一个参数。申报 静态方法,请使用以下习惯用法:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 
@staticmethod
表单是一个函数 –请参见以下内容的说明: 有关详细信息,请参阅中的函数定义

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

Python中的静态方法类似 那些在java或C++中发现的。暂时 更高级的概念,请参阅 在本节中


@修饰符是在python 2.4中添加的,如果您使用的是python<2.4,则可以使用classmethod()和staticmethod()函数

 @classmethod
 def some_class_method(cls, *args, **kwds):
     pass
例如,如果要创建工厂方法(函数返回类的不同实现的实例,具体取决于它得到的参数),可以执行以下操作:

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和静态方法的好例子, 静态方法显然属于类,因为它在内部使用类集群。 classmethod只需要关于类的信息,而不需要对象的实例

使
\方法成为classmethod的另一个好处是\u cluster\u,这样子类就可以决定更改其实现,可能是因为它非常通用,可以处理多种类型的集群,所以仅检查类的名称是不够的

Python中@staticmethod和@classmethod的区别是什么? 您可能已经看到过类似此伪代码的Python代码,它演示了各种方法类型的签名,并提供了一个docstring来解释每种方法:

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_方法
。这就是所谓的“实例方法”。当使用实例方法时,它被用作部分函数(与total func相反)
>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
>>> 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'
# 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}
>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
>>> 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'>
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
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()
# A.run_self() #  wrong
A.run_static()
A.run_class()
class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"
class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
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()
@staticmethod
def some_static_method(*args, **kwds):
    pass
 @classmethod
 def some_class_method(cls, *args, **kwds):
     pass
class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name
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, "")
@staticmethod  
def validate_name(name):
    return len(name) <= 20
Person.validate_name("Gaurang Shah")
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 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',)
#!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)
'''
"""
def f(self, x, y)
@classmethod
def f(cls, x, y)
@staticmethod
def f(x, y)
class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner
@classmethod
@staticmethod
@property
class DecoratorTest(object):

    def __init__(self):
        pass

    def doubler(self, x):
        print("running doubler")
        return x*2

    @classmethod
    def class_doubler(klass, x):
        print("running doubler: %s" % klass)
        return x*2

    @staticmethod
    def static_doubler(x):
        print("running quad")
        return x*2

decor = DecoratorTest()
print(decor.doubler(5))
# running doubler
# 10

print(decor.class_doubler(5))
# running doubler: <class '__main__.DecoratorTest'> 
# 10
print(DecoratorTest.class_doubler(5))
# running doubler: <class '__main__.DecoratorTest'> 
# 10

print(DecoratorTest.static_doubler(5))
# running doubler 
# 10
print(decor.static_doubler(5))
# running doubler 
# 10

print(decor.doubler)
# <bound method DecoratorTest.doubler of <__main__.DecoratorTest object at 0x7f90e74fd150>> 
print(decor.class_doubler)
# <bound method DecoratorTest.class_doubler of <class '__main__.DecoratorTest'>> 
print(decor.static_doubler)
# <function DecoratorTest.static_doubler at 0x7f90e7447440> 
class Employee:

    NO_OF_EMPLOYEES = 0
  
    def __init__(self, first_name, last_name, salary):
        self.first_name = first_name
        self.last_name = last_name
        self.salary = salary
        self.increment_employees()

    def give_raise(self, amount):
        self.salary += amount

    @classmethod
    def employee_from_full_name(cls, full_name, salary):
        split_name = full_name.split(' ')
        first_name = split_name[0]
        last_name = split_name[1]
        return cls(first_name, last_name, salary)

    @classmethod
    def increment_employees(cls):
        cls.NO_OF_EMPLOYEES += 1

    @staticmethod
    def get_employee_legal_obligations_txt():
        legal_obligations = """
        1. An employee must complete 8 hours per working day
        2. ...
        """
        return legal_obligations
employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.first_name)
print(employee_1.salary)

'Andrew'
85000
employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(employee_2.first_name)
print(employee_2.salary)

'John'
95000
employee_1 = Employee('Andrew', 'Brown', 85000)
employee_2 = employee_1.employee_from_full_name('John Black', 95000)
employee_1 = Employee('Andrew', 'Brown', 85000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')
employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')

Number of employees: 1
Number of employees: 2
print(Employee.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...
employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...
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()
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()