zoukankan      html  css  js  c++  java
  • ~~面向对象进阶(四):双下划线方法~~

    进击の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解释器来执行

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


    *有点东西*
    *继续深究*
  • 相关阅读:
    微信小程序HTTPS
    微信商城-1简介
    va_list
    Event log c++ sample.
    EVENT LOGGING
    Analyze Program Runtime Stack
    unknow table alarmtemp error when drop database (mysql)
    This application has request the Runtime to terminate it in an unusual way.
    How to check if Visual Studio 2005 SP1 is installed
    SetUnhandledExceptionFilter
  • 原文地址:https://www.cnblogs.com/jevious/p/11264615.html
Copyright © 2011-2022 走看看