python从__new__开始(3)静态方法和类方法

首先,你要明白什么是装饰器

之前写过一篇,水平有限,不明不白,如果不懂,自行百度。

静态方法和类方法都是装饰器。

先贴段官方文档:https://docs.python.org/3/library/functions.html

本文参考原文以及图片来自于:https://www.pythoncentral.io/difference-between-staticmethod-and-classmethod-in-python/

@staticmethod

改变方法为静态方法

一个静态方法不需要收到一个明确的第一参数(类中的self)。用下面的语法来声明静态方法:

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

再次说明,可以不写参数,不必要传self(一般类中的函数都是要传self的)

@staticmethod本质是个个装饰器——在函数定义中查看函数的描述的详细说明。

他可以在类上(C.F())或者一个实例(C().F())上被调用,类以外的实例被忽略。

扫描二维码关注公众号,回复: 4268641 查看本文章

静态方法在Python中与他在Java或者C++中很相似。同样的看classmethod用来创造类的构造器。

就像装饰器一样,他同样可以调用静态方法像常规的函数一样,并用他的结果做点什么。在一些情况下需要从类本体中引用函数,并且希望避免自动转换为实例方法。对于这样的情况,可以这么写:

class C:
    builtin_open = staticmethod(open)

@classmethod

转换一个方法为类方法

一个类方法接收class作为一个明确的第一参数(cls),就像一个实例方法收到实例一样。声明一个类方法如下:

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

@classmethod本质是个个装饰器——在函数定义中查看函数的描述的详细说明。

他可以在类上(C.F())或者一个实例(C().F())上被调用,类以外的实例被忽略。如果一个类方法被派生类方法调用,派生类对象忽略第一个参数。

类方法和C++或者Java的静态方法不同。如果你需要他们,参考静态方法。

上面两段介绍来自文档,基本介绍了静态方法和类方法是什么,如果不懂继续往下看。

类的运行流程



1和2步为类Kls的方法传递了参数
在第3步self参数提供了实例。

第4步,我们不需要为方法提供实例,解释器会帮我们做这些的。

我们会发现,其实这两个方法,本质上就是在跟实例化这个问题较劲了。

类像一个门一样,门里的方法调用门里的变量,用self.变量名,门外的方法调用门外的变量,直接用变量名。门外的方法怎么调用门里的变量呢?门里的方法怎么调用门外的变量呢?

@classmethod

门外的方法调用门里的变量

把类封在方法里就好了。

def get_no_of_instances(cls):
    return cls.no_inst
 
class Kls(object):
    no_inst = 0 
    def __init__(self):
        Kls.no_inst = Kls.no_inst + 1

print(get_no_of_instances(Kls))

很简单对不对?但是写在类外面不好看,毕竟是和类相关的方法,我们如何写在类里面呢?

class Kls(object):
    no_inst = 0
 
    def __init__(self):
        Kls.no_inst = Kls.no_inst + 1
 
    @classmethod
    def get_no_of_instance(cls):
        return cls.no_inst

    def get_no_of_instance2(self):
        return self.no_inst
 
ik1 = Kls()
 
print(ik1.get_no_of_instance())
print(Kls.get_no_of_instance())

print(ik1.get_no_of_instance2())
print(Kls.get_no_of_instance2(ik1))

print(Kls().get_no_of_instance2())
print(Kls.get_no_of_instance2(ik1))
#print(Kls.get_no_of_instance2())

on_inst表示了实例化的次数,运行代码你会发现,只有ik1=Kls()和倒数第三行Kls实例化了。

其实这就是类方法。不但写在类里面,调用的时候跟其他的方法保持一致,并且没有实例化,很漂亮对不对?颜值决定一切!

这里我补充了个get_no_of_instance2(self)方法,大家可以很容易发现正常调用应该怎么写,最后一行是仿写调用classmethod的,会报错。倒数第二行我们要传一个实例ik1。

接着我们说静态方法,你从文档的介绍来看,应该感觉跟类方法差不多的。

@staticmethod

门里的方法调用门外的变量

直接用嘛,干嘛那么麻烦。

IND = 'ON'
 
class Kls:
    def __init__(self,data):
        self.data = data
    def do_reset(self):
        if IND == 'ON':
            print('Reset done for:', self.data)
    def set_db(self):
        if IND == 'ON':
            self.db = 'new db connection'
        print('DB connection made for:',self.data)
 
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()

错了,不好意思,我们的问题不在这里,问题在于流畅的交互,从上面的例子可以看出来,不但可以直接使用,我们也可以在init中data的地方传进来,如果是变量,还好,如果是个function呢?

实际上静态方法应用的背景是:如果有一个function的内容跟class无关,也就是说不会调用class的任何方法,但是却又经常或者只被这个class调用,我可能会认为,他应该属于这个class(写在class里面),既然无关,self会显得多余啊!class外部还要调用这个方法。(比如log,或者error这样的)当然宗旨还是为了漂亮!

IND = 'ON'
 
class Kls:
    def __init__(self, data):
        self.data = data
 
    @staticmethod
    def checkind():
        return (IND == 'ON')
 
    def do_reset(self):
        if self.checkind():
            print('Reset done for:', self.data)
 
    def set_db(self):
        if self.checkind():
            self.db = 'New db connection'
        print('DB connection made for: ', self.data)
 
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()
print(Kls.checkind())

代码写多了就会发现,归类的重要性。。。

最后,再做一组对比

class Kls(object):
    def __init__(self, data):
        self.data = data

    def printd(self):
        print(self.data)

    @staticmethod
    def smethod(*arg):
        print('Static:', arg)

    @classmethod
    def cmethod(*arg):
        print('Class:', *arg)
        
    @classmethod
    def cmethod(self, *arg):
        print('Class:', self, *arg)

ik = Kls(23) 
ik.printd()
ik.smethod()
ik.cmethod()
# Kls.printd()
Kls.smethod()
Kls.cmethod()


猜你喜欢

转载自blog.csdn.net/wwx890208/article/details/80661419