Mrli
别装作很努力,
因为结局不会陪你演戏。
Contacts:
QQ博客园

staticmethod和classmethod区别

2019/09/15 Python
Word count: 1,532 | Reading time: 6min

staticmethod和classmethod

类的实例化基本遵循创建实例对象、初始化实例对象、最后返回(产生)实例对象这么一个过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Test(object):
data = 'world' # 类对象的数据成员

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

@staticmethod # 静态方法,不能访问类数据成员
def func():
print("hello")

@classmethod # 类方法,能访问类数据成员
def getData(cls):
print(cls.data)

if __name__ == '__main__':
t = Test('A')
Test.func()
Test.getData()

共同:

  • 两个都是装饰器,装饰的成员函数可以通过类名.方法名(...)来调用

区别:

  • ▲最显著的特点是classmethod需要传递一个参数cls,而staticmethod不需要。因此可以访问、修改类的属性,类的方法,实例化对象等,避免硬编码;而staticmethod不行
  • classmethod可以判断出自己是通过基类被调用,还是通过某个子类被调用

用途:

  • classmethod多用于设计模式之工厂模式,将解析逻辑封装在方法本身内部。(也可认为构造前交互,即在进行实例化类对象之前先进行某些逻辑操作,即可看作进行不同的构造函数,然后返回一个类实例,见具体代码),更多拓展见附录__new____init__
  • staticmethod用法就跟其他的语言中的静态static用法相同(可看作是属于该类的一个工具、辅助函数)

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Python program to demonstrate  
# use of class method and static method.

class time(object):
def __init__(self, year):
super(time, self).__init__()
self.year = year
print(self.year)

# a class method to create a time that one day following the data 'year'
@classmethod
def tomorrow(cls,year):
print(type(cls)) # >>> ▲ Python所有类都继承自`<class 'type'>`,包括新式类`object`
return cls(year+1)

# a static method to check whether the given data 'year' is after 2000.
@staticmethod
def twoThoundYear(year):
return year>2000


if __name__ == '__main__':
t1 = time(1999)
t2 = time.tomorrow(1999)
print( time.twoThoundYear(2001) )

可看下这篇class method vs static method in Python

附录__new____init__

知识点

▲1. 首先要弄懂调用顺序__new__–>__init__: 所以__init__其实不是实例化一个类的时候第一个被调用 的方法。当使用 Persion(name, age) 这样的表达式来实例化一个类时,最先被调用的方法 其实是__new__方法。

__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供(实例化时加的参数,也会被认为时cls的属性,见①)。即系统知道__new__() 方法始终都是类的类方法,即使没有被加上类方法装饰器。

__new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。

▲2. __init__有一个参数self,就是这个__new__return的实例__init____new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值。而__new__必须有(可以return父类__new__出来的实例,或者直接是object的__new__出来的实例)。__new__方法决定了创建哪个类的实例(可以是父类,也可以是子类),因此不一定调用当前类的__init__。即(若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行)

3.继承自object的新式类才有__new__,同时,在任何新式类的__new__()方法,不能调用自身的__new__()来制造实例,因为这会造成死循环,即class Foo(object)__new__中不能Foo.__new__(cls, *args, **kwargs)。

区别

1.__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。

2.__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。

依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A(object):    # 新式类:继承自object
def __init__(self,something):
print('init')
print(something)

# def __new__(cls): 不行,因为A("...")参数不匹配
# pass

def __new__(cls, *args, **kwargs):
print('new')
self = object.__new__(cls) # ①cls中包含了*args, **kwargs信息
self.x = '1'
return self # 调用父类的`__new__`方法会返回一个A对象,init里的参数self调用的就是这个self实例
# `__new__`必须具有返回值,否则无法创建对象,因为`__init__`函数需要这个返回值
# 自己在定义`__new__`的时候,参数要与`__init__`函数的参数匹配,我可以不用到这些参数,但一定要匹配。或者可以使用*arg和**args的形式。

if __name__ == '__main__':
# a = A.__new__(A) #>>> new
a = A('do it') # >>> new init
print(a.__dict__) # {'x': '1'}
# 2、new定义在type元类中,必须具有返回值,
# 3、new的作用就是创建实例,然后将创建的实例传递给init进行初始化

总结: a = A() --> __new__方法,return调用父类__new__生成一个类实例对象 -->__init__(self,...)中的self实例就是这个父类__new__出来的实例

__new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() 启动之前,__new__() 决定是否要使用该 __init__() 方法,因为__new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。

__new__来实现设计模式中的–单例模式

只能实例化一个类对象

1
2
3
4
5
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls.instance

▲ Python所有类都继承自<class 'type'>,包括新式类object

Author: Mrli

Link: https://nymrli.top/2019/07/07/staticmethod和classmethod区别/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
自动化运维工具Ansible
NextPost >
yaml基础语法_spring_boot
CATALOG
  1. 1. staticmethod和classmethod
    1. 1.0.1. 共同:
    2. 1.0.2. 区别:
    3. 1.0.3. 用途:
      1. 1.0.3.1. 具体代码
  2. 1.1. 附录__new__和__init__
    1. 1.1.1. 知识点
    2. 1.1.2. 区别
    3. 1.1.3. 用__new__来实现设计模式中的–单例模式