美文网首页
从self、cls看Python的实例化

从self、cls看Python的实例化

作者: 点点寒彬 | 来源:发表于2018-11-05 00:53 被阅读160次

    背景

    刚开始学习Python的时候经常会有一个疑问,为什么每个类方法的第一个参与一定要加一个self?经过一定的编码后发现,怎么还有一些类方法里面写的是cls

    实例化

    在使用类方法的时候,我们通常会把一个类做实例化之后再进行调用,比如这样:

    class Calc(object):
        def add(self, x, y):
            print x + y
    
    
    if __name__ == '__main__':
        calc = Calc()
        calc.add(1, 1)
    

    这个self到底是什么呢?我们加两行代码来看。

    class Calc(object):
        def add(self, x, y):
            print x + y
            print self
    
    
    if __name__ == '__main__':
        calc = Calc()
        calc.add(1, 1)
        print calc
        
    --->
    2
    <__main__.Calc object at 0x108b4e4d0>
    <__main__.Calc object at 0x108b4e4d0>   
    

    可以看的出来,这个self和实例化出来的calc都是Calc这个对象,并且指向的内存地址是同一个,也就是他们两个是同一个东西。

    静态方法

    在看别人的代码的时候,经常会看到一个@staticmethod。这个东西是静态方法,在类中的方法都必须要传self对象,但是一旦被@staticmethod装饰器装饰后的方法,就不需要传入self这个参数,如下:

    class Calc(object):
        def add(self, x, y):
            print x + y
    
        @staticmethod
        def minus(x, y):
            print x - y
    
    
    if __name__ == '__main__':
        calc = Calc()
        calc.add(1, 1)
        Calc.minus(3, 2)
    

    具体来说这个有什么用?我个人理解来说在Python这个装饰器只是一个基于类设计的一个方法。你用一个def来实现,或者就用类方法来实现影响其实并不大。当然,你实例化了,也是可以通过实例来调用静态方法的。

    类方法

    Python中还有一个方法@classmethod,使用了这个方法,传入的第一个参数就不是self,而是cls。比如这样:

    class Calc(object):
        def add(self, x, y):
            print x + y
    
        @staticmethod
        def minus(x, y):
            print x - y
    
        @classmethod
        def multi(cls, x, y):
            print x * y
    
    
    if __name__ == '__main__':
        calc = Calc()
        calc.add(1, 1)
        Calc.minus(3, 2)
        calc.multi(2, 2)
        
    --->
    
    2
    1
    4   
    

    可以在这行代码中吧这个cls打出来看看是个什么东西,最为对比,同样也加上打印self

    <class '__main__.Calc'>
    <__main__.Calc object at 0x1033ef4d0>
    

    这样对比出来就非常清晰了。cls指的是这个类,如果严谨一点可以再加上print Calc。而self是这个类的一个实例,是放在内存中的。

    那么这个到底有什么用呢?说实话,一般来说没什么卵用,跟@staticmethod一样。可以在不需要实例化的时候调用这个方法。

    划重点

    如果你需要经常对函数的结构进行修改,那么这个方法就非常有用了。

    英文好的可以看这里Meaning of @classmethod and @staticmethod for beginner?

    英文不好的就看这里Python 中的 classmethod 和 staticmethod 有什么具体用途? - 水中柳影的回答 - 知乎

    实例化的过程

    理解了selfcls是什么时候,可以继续再研究实例化的过程。

    Python在实例化的过程中,会首先调用__new__这个内置的方法。如果我们重写这个方法,但是不按照原有的方式去写,那么就会实例化失败,比如这样:

    class Calc(object):
        def __init__(self):
            print "class init..."
    
        def __new__(cls, *args, **kwargs):
            print "new a class..."
    
        def add(self, x, y):
            print x + y
    
    
    if __name__ == '__main__':
        calc = Calc()
        print calc
        
    --->
    new a class...
    None
    

    可以看到,实例化了一个None出来。
    __new__方法总增加return object.__new__(cls)即可正常实例化。同时可以看到__init__方法也被执行了。

    特别说明一下,这个objectPython所有的新式类的基类。

    单例

    了解了这些内容,重新来看看单例模式。之前介绍了一个不严谨的单例,这里来看一个比较严谨的单例示例。

    class Single(object):
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls, '_single'):
                cls._single = object.__new__(cls, *args, **kwargs)
            return cls._single
    

    这里可以看到在__new__方法中加了一个判断,如果类实例化的时候没有_single这个属性,说明类还没有被实例化,这个时候就按照正常的方法实例化,如果发现有_single这个属性了,那么就直接返回类的_single对象,也就是已经被实例化的对象,通过这个逻辑来保证实例化的时候,只会存在一个实例。

    相关文章

      网友评论

          本文标题:从self、cls看Python的实例化

          本文链接:https://www.haomeiwen.com/subject/jcljxqtx.html