~~面向对象进阶(四)——双下划线方法~~

时间:2020-12-15 17:21:44

进击のpython


类的双下划线方法


双下划线方法是类的特殊方法,是由双下划线加方法名加双下划线进行定义的

而这样的写法就表示,它其实是有特殊意义的

(没有特殊意义我提他干撒,不是神经病嘛)

其实啊,双下划线方法更多是python的源码开发者使用的

他们在写源码的时候,会采用这种双下划线方法

但是我建议在开发的时候尽量少使用这种方法

那尽量少使用,为什么还要说呢?

这是因为,学一下这种方法,可以帮助我们更好地理解源码

放心兄弟

你要是没读过一两个源码,那算你口技好

源码可是必须要翻过去的山┗|`O′|┛ 嗷~~

来吧,既然是了解,就不会很细


  • 大概了解的方法

    len方法

    这个方法很熟悉吧

    其实我们在计算什么字典啊列表之类的长度的时候

    表面上写的是len()

    实际上是在调用--len--方法

    正常我们在执行这个函数的时候是这样的

    l = [1, 2, 3, 4, 5]
    
    print(l.__len__())
    print(len(l))

    结果喜闻乐见,两个5是吧,

    但是我要是将他的方法进行修改

    class Demo(object):
        def __len__(self, obj):
            print("我是len方法")
            return 1
    
    
    l = Demo()
    print(l.__len__([1, 2, 3, 4, 5]))

    (为什么要写return呢? 是因为要求的,不写就会报错)

    你打印的结果,还是5嘛?

    是不是就不是了

    所以说,这个len()在执行的时候,实际上是在调用双下划线len方法


    hash方法

    其实和楼上的len方法相同

    这个方法就是调用了内部的--hash--方法

    仿照上面的写一个!


    item系列

    这个系列,我想说一个大家都很熟悉的东西

    字典

    你有想过字典是怎么赋值调用的吗?

    其实用的都是双下划线方法

    话不多说直接上代码

    class Dic:
        # def __init__(self, name):
        #     self.name = name
    
        def __getitem__(self, item):
            print("获取KEY", item)
            print(self.__dict__[item])
    
        def __setitem__(self, key, value):
            print("设置一个key...", key)
            self.__dict__[key] = value
    
        def __delitem__(self, key):
            print('执行del时,我执行')
            self.__dict__.pop(key)
    
        def __delattr__(self, item):
            print('删除的时候我执行')
            self.__dict__.pop(item)
    
    
    b = Dic()
    b[1] = 1
    b[2] = 2
    del b[2]
    b[3] = 3
    b[3]
    print(b.__dict__)

    执行结果如下:

    设置一个key... 1
    设置一个key... 2
    执行del时,我执行
    设置一个key... 3
    获取KEY 3
    3
    {1: 1, 3: 3}

    所以说,字典的相关操作,实际上是在调用相应的双下划线方法


  • 重点掌握的方法

    str&repr

    这两个方法应该知道吧

    (要是不知道就回去看博客吧凑弟弟)

    那我们在使用它的时候实际上调用的就是对应的双下划线方法

    举个例子

    class R:
        def __init__(self, item):
            self.item = item
            pass
    
    s = R("ponny")
    
    print(str(s))
    print(repr(s))

    可以看到打印出来的其实都是相对应的内存地址

    <__main__.R object at 0x0548FF50>
    <__main__.R object at 0x0548FF50>

    现在我们自己这两个相对应的双下划线方法

    看看是不是对这两个函数有影响

    class R:
        def __init__(self, item):
            self.item = item
            pass
    
        def __str__(self):
            print(f"我是{self.item}的str方法!")
            return "A"
    
        def __repr__(self):
            print(f"我是{self.item}的repr方法!")
            return "B"
    
    
    s = R("ponny")
    
    print(str(s))
    print(repr(s))

    当我们执行上面的语句的时候

    应该得到的是这样的结果

    我是ponny的str方法!
    A
    我是ponny的repr方法!
    B

    说明什么?

    说明这两个方法的使用确实是调用python内部同名的双下划线方法

    而我们在局部空间自己定义了这个方法

    根据加载顺序,先加载的就是我们写好的

    所以说,也可以说明这两个方法其实是调用对应的双下划线方法

    其实还有一点想要说的

    当我把str方法注释掉再执行

    会发生什么现象呢?

    class R:
        def __init__(self, item):
            self.item = item
            pass
    
        # def __str__(self):
        #     print(f"我是{self.item}的str方法!")
        #     return "A"
    
        def __repr__(self):
            print(f"我是{self.item}的repr方法!")
            return "B"
    
    
    s = R("ponny")
    
    str(s)
    print(str(s))

    结果是这样的:

    我是ponny的repr方法!
    我是ponny的repr方法!
    B

    说明什么?

    当我们解释器中要是没有str双下划线方法的时候

    在使用str方法时,就会使用repr的双下划线方法

    然后其实还有一点就是

    其实你可能也注意到了

    这两个方法的返回值必须是字符串,否则会报错

    (要是感兴趣你可以自己去上网查一下相关资料)


    del 析构方法

    析构方法,当对象在内存中被释放时,自动触发执行

    怎么理解呢?

    我现在搞一个这样的代码

    class R:
        def __init__(self, item):
            self.item = item
            pass
    
        def __del__(self):
            print("我是del...")
            pass

    当我对这个类进行实例化会发生什么呢?

    s = R("ponny")

    执行结果如下:

    我是del...

    欸?

    我不是没有执行这个方法嘛?

    怎么还会执行啊??

    我们先把这个疑问放在这

    我们在这实例化的后面

    加上一个打印语句

    看看会打印什么??

    print("我是后面的语句")

    结果你可能大概想到(猜到)了

    我是后面的语句
    我是del...

    所以说为什么会是这个执行顺序呢?

    前面我们说了,del是个析构方法

    而析构方法就是对象在内存中被释放了就会自动执行

    当py文件的所有东西都执行完了的时候

    在内存中储存的对象就会自动释放

    (这是python的垃圾回收机制导致的)

    从而就会触发del方法

    而del方法的本质就是双下划线的del方法

    所以,就在最后执行了那个打印语句

    但是呢

    此方法一般无须定义,因为Python是一门高级语言

    程序员在使用时无需关心内存的分配和释放

    因为此工作都是交给Python解释器来执行

    所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的


*有点东西*
*继续深究*