python @classmethod

文章详细介绍了Python中的classmethod,它是用来指定类方法的修饰符,常用于解决多个构造函数的问题,以及在实例化前与类交互的场景。classmethod作为类方法,可以在不实例化类的情况下调用,支持多态,并在继承时保持子类实例化。文章通过例子解释了classmethod在插件系统和日期处理类中的应用,强调了其在重构和扩展性中的价值。
摘要由CSDN通过智能技术生成

1..什么是classmethod

classmethod是用来指定一个类的方法为类方法

长的像下面这个样子

1

2

3

class cc:

    @classmethod

    def f(cls, arg1, arg2, ...): ...

cls通常用作类方法的第一参数  跟self有点类似( __init__里面的slef通常用作实例方法的第一参数)。即通常用self来传递当前类对象的实例,cls传递当前类对象。

self 和cls 没有特别的含义,作用只是把参数绑定到普通的函数上, 不一定非得是slef 或cls   , 可以换成别的xxx

2..为什么会出现classmethod

(下面的比较琐碎,也不讲章法,但是这些点点滴滴我想记录下来,因为他们帮助我拼凑了这类知识的框架体系。我很喜欢用拼凑这个词,每次碰到一个完全陌生的鬼,总是这儿点点,那儿翻翻,每个足迹都会留下一点点碎片,慢慢的,逛的久了,再动手写写,基本上这一类内容在我脑子里渐渐形成个轮廓了,这个轮廓就是这些碎片拼凑出来的)

1--classmethod设计的目的是什么呢?事实上与Python面向对象编程有关的,由于Python不支持多个的參数重载构造函数,比方在C++里,构造函数能够依据參数个数不一样。能够写多个构造函数。Python为了解决问题,採用classmethod修饰符的方式,这样定义出来的函数就能够在类对象实例化之前调用这些函数,就相当于多个构造函数,解决多个构造函数的代码写在类外面的问题。

2---类最基本的作用是实例化出一个对象,但是有的时候再实例化之前,就需要先和类做一定的交互,这种交互可能会影响实际实例化的过程,所以必须放在调用构造函数之前。大概也可能是因为这个原因出现了classmethod

3---直接一点来说,我们知道对于一个普通的类,我们要使用其中的函数的话,需要对类进行实例化,而一个类中,某个函数前面加上了staticmethod或者classmethod的话,那么这个函数就可以不通过实例化直接调用,

可以通过类名进行调用的

4---@classmethod 定义的类方法是可选构造函数中,我们定义了一个类方法,类方法的第一个参数(cls)指代的就是类本身。类方法会用这个类来创建并返回最终的实例。使用类方法的另一个好处就是在继承的时候,保证了子类使用可选构造函数构造出来的类是子类的实例而不是父类的实例。

3..classmethod有什么用

在Java等语言中,这类功能通常通过工厂类(Factory)实现,先初始化一个工厂类的实例,然后由这个工厂类的实例构造实际需要的实例。在Python中,普通类完全可以替代Factory,而对于支持配置的Factory,就对应到相应的classmethod。

Python中的classmethod(和staticmethod)并不止拥有美学上(或者命名空间上)的意义,而是可以实际参与多态的、足够纯粹的OOP功能,原理在于Python中类可以作为first class的对象使用,很大程度上替代其他OOP语言中的工厂模式。classmethod既可以作为factory method提供额外的构造实例的手段,也可以作为工厂类的接口,用来读取或者修改工厂类本身。classmethod还可以通过额外的类引用,提供继承时的多态特性,实现子类挂载点等。




 

4..举第一个例子来理解classmethod

(因为我功力太浅,我真的没能理解@classmethod所起到的作用,但是知乎灵剑的这篇博客不明觉历,我还是先把这个例子这,说不定哪一天就想通了)

 1)有一个插件系统,可以自动从插件目录中加载外部插件

 

2)Plugin是用户自定义插件的基类,它的构造函数接受一个api_interface的参数,把它保存到实例中。当想用这个接口的时候,调callback就好了,达到扩展功能的目的

3)事情不可能一成不变,要升级了,需要重新设计插件系统

4)插件数量变更多了,每个插件只干自己的事(比如,比如缝纫机插件只管缝衣服的事情,盖房子插件只管盖房子的事,警察插件只管抓坏人的事),那希望安装注册插件的时候希望插件声明好自己只干哪几样活(比如挖土插件要说好 :我只负责挖土,不负责缝衣服和盖房子)。

5)api_interface也变了,但是希望旧接口不做任何改变就能直接用

6)旧插件也不做任何改动就可以继续使用。

7)基于这样的需求,我们需要在构造plugin对象之前,就先从类中获取一定的信息。

 

5..再举个例子来理解classmethod的使用方法

这个是CSDN的dyh4201,链接都放下面了,这个通俗易懂,总感觉@classmethod还能发挥更大的用途,只是我还没完全参透,举不出例子来

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

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

看下面的定义的一个时间类:

  

class Data_test(object):

    day=0

    month=0

    year=0

    def __init__(self,year=0,month=0,day=0):

        self.day=day

        self.month=month

        self.year=year

    def out_date(self):

        print "year :"

        print self.year

        print "month :"

        print self.month

        print "day :"

        print self.day

t=Data_test(2016,8,1)

t.out_date()

输出:

year :

2016

month :

8

day :

1

符合期望。

  

如果用户输入的是 "2016-8-1" 这样的字符格式,那么就需要调用Date_test 类前做一下处理:

  

string_date='2016-8-1'

year,month,day=map(int,string_date.split('-'))

s=Data_test(year,month,day)

先把‘2016-8-1’ 分解成 year,month,day 三个变量,然后转成int,再调用Date_test(year,month,day)函数。 也很符合期望。

  

那我可不可以把这个字符串处理的函数放到 Date_test 类当中呢?

  

那么@classmethod 就开始出场了

  

class Data_test2(object):

    day=0

    month=0

    year=0

    def __init__(self,year=0,month=0,day=0):

        self.day=day

        self.month=month

        self.year=year

    @classmethod

    def get_date(cls,data_as_string):

        #这里第一个参数是cls, 表示调用当前的类名

        year,month,day=map(int,string_date.split('-'))

        date1=cls(year,month,day)

        #返回的是一个初始化后的类

        return date1

    def out_date(self):

        print "year :"

        print self.year

        print "month :"

        print self.month

        print "day :"

        print self.day

在Date_test类里面创建一个成员函数, 前面用了@classmethod装饰。 它的作用就是有点像静态类,比静态类不一样的就是它可以传进来一个当前类作为第一个参数。

  

那么如何调用呢?

  

r=Data_test2.get_date("2016-8-6")

r.out_date()

输出:

year :

2016

month :

8

day :

1

这样子等于先调用get_date()对字符串进行出来,然后才使用Data_test的构造函数初始化。

  

这样的好处就是你以后重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,然后使用装饰符 @classmethod 就可以了。

 6.在继承时也能工作的很好:

类方法的一个主要用途就是定义多个构造器。它接受一个class 作为第一个参数(cls)。在继承时也能工作的很好:

7..还有其他待挖掘

关于@classmethod,以后要是发现新的用途或者有更深的理解了,我再继续加到下面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mmnnnbb123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值