• Python魔法方法(在合适的时间,python自动调用如下方法魔法方法)


    此前我们已经解除了Python中最常用的魔法方法:__init__

    什么时候调用__init__? 答:我们想在对象实例化的时候就赋某些值就重写它呗!就是看需求,有需要就重写,没需要就不重写呗,不重写就是啥也没有呗!嗯~对的!

    *__init__(self[,...])

      __init__是不可以设置返回值的,他只能默认的返回None,如果试图给它设置返回值,会出现TypeError的异常

     *__new__(cls[,...])

      实际上实例化一个类的时候第一个调用的不是__init__方法,而是这个__new__方法

      ·他和其他实例化方法不同,他的第一个参数是类和self一样就写cls,如果后面有参数,后面的参数会原封不动的传给__init__方法

      ·__new__返回一个实例对象,可以是这个类的实例对象也可以是其他类的实例对象

      ·一般情况下我们极少的会去重写这个__new__方法

     

      ·但是在继承了不可改变的父类的时候,new方法就显得尤为重要了

       因为init只能返回None,因此我们设置这个new去掉用不可改变的父类中的方法,如下我想把所有的字符串都变成大写显示

      我发现这样写也行[但是上方那样还写,只修改了传入的string,而其他的str方法继续用,而下方的可能就没了把,不太清楚,如果用还是按照上方那样用]

       实际上通过__init__方法也可以实现,只不过不能直接返回,而是通过函数调用出来,但是他不调用方法,实例化返回的还是aaa,而new实例化返回的就是我们所设定好的全部大写了!!,可见还是有很大区别的。

             

     *__del__(self)

      当对象【内存】被销毁的时候,这个方法会被自动的调用

     

      他是当垃圾回收机制回收的时候,他才会调用这个对象的del方法,因此下图等号不成了(并不是我们调用del方法,他就会调用__del__方法)

     

     

               工厂函数

         ~~~算数运算~~~~【个人觉得这东西知道怎么用即可,随着学习的深入可能以后会用到】

     

       当你调用加法是会自动调用__add__方法,调用减法的时候会自动调用__sub__方法...

     

      但是注意了,下图这样会报错【报错的原因是无线递归,因为self是实例化对象,other是执行方法是另一个参数对象,而self是由这个类实例化的,因此当执行到(return self + other)的时候,会调用__add__方法,如此一直调用,停不下来!】

             

      解决方法:将self转化成int,不当成这个类的对象,则不会调用该类的__add__方法了

      

     

     什么是反运算呢?

    如a+b,而a没有__add__方法,则会执行b的__radd__方法:

    如下图:数字1没有__add__方法,因此会执行a对象中的的__radd__方法 #如果俩个都是数字没有,个人理解是默认是int,但是这个int优先级比Nint低,为什么呢?因为Nint继承自int,而int内置方法没有写出来,优先级比较低,直接写出来的radd方法优先级高。  先这样写看看以后怎么说!!!

    下图中在(1+a)中调用radd方法的self指的就是a对象,而other才是1

         

             增量赋值运算

     

                 简单定制

     

     *__str__(self)

      #print这个实例化对象走的就是__str__()

     *__repr__(self)

      #没有重新定于__new__方法,实例化对象直接返回的就是__repr__()

    #调用new是最强的,有它在实例化后返回的一定是new返回的,如果没有它,则是repr返回的 #Nxj自己测试的结果 【但是new还是很少用的嘛,还是需要多看多练加强记忆别搞混】

      

    localtime()返回的的是如下的元组结构:

    其实写的有问题,就是比如说开始时间是是16:25:50 结束时间是16:26:04 ,那么返回的是个负数

    解决思路应该是如果是负数说明最起码最前面的第一项一定大【16:26:50~~17:22:05】【如果不全部化成秒的话】,如果发现这个是负数,就用60+上这个负数返回,相应的需要把end的数组这个的前一项数值-1 ,对于分钟也是这样,而对于小时就是+12 了,一直到年,【一直到年还是恐怖的,一般不会的-_-||】

    扩展【纠正】一下以前写的,以前写的是没错,但是针对于self.这样来写属性的话,属性名和方法名相同的话,属性会覆盖方法,而以前写得的是谁在下面谁优先级高恢复高以前的,这个写的也没错,但是谁在下面谁覆盖上面针对的属性是不带self的

    就是!:如果一个类中含有self.name1=属性  与def name1():   无论谁在前在后,self.name1属性是会覆盖name1的方法的

    而如果是name 与 def name1():  谁在前谁被覆盖!这个应该没问题

    针对的主要是self内!!!

    报的异常:

    在此提醒:类中的属性不能被变更为方法!!!切记切记!!这个属性指的是self下的属性!!也需要切记切记!!!

    小甲鱼这个写法可比我简单啊 这个思路虽然跟我很像,但是我感觉这样写好巧啊,省了好多的代码啊 好清晰!!

    下面这个和我上面一样没考虑时间为负值哦

     

     方法前加一个下划线变成伪私有,属性前加俩个下划线变成伪私有

    下方这个是我搞出的最终版

    import time as t
    
    class Mytimer:#self所有指的都是我实例化出来的!(那个对象)!,无论在哪个方法内的self都一样
        #相加
        def __add__(self,other):
            self.prompt="二者总共持续了"
            result=[]
            for i in range(0,6):
                result.append(self.arr[i]+other.arr[i])
                if result[i]:#如果不是0
                    self.prompt+=str(result[i])+str(self.unit[i])
            return self.prompt
        #事先定义防止出错
        def __init__(self):
            self.prompt="未调用stop()方法"
            self.begin=0
            self.end=0
            self.unit=['','','','小时','分钟','']
            self.arr=[0,0,0,0,0,0]#这个是为了解决__add__方法如果运行方法,防止报错,没运行让他为就好
        #print出来显示
        def __str__(self):
            return self.prompt
    
        #实例化对象返回出来
        __repr__=__str__
        
        #计时开始
        def start(self):
            print("计时开始...")
            self.begin=t.localtime() #这里不能写start否则类的属性会使得start方法失效
    
        #计时结束
        def stop(self):
            #print(self)
            if not self.begin:#没有!self.begin这样写的哦
                print("请先调用start()方法")
            else:
                self.end=t.localtime()
                self._lasttime()
                print("计时结束")
    
        #持续时间
        def _lasttime(self):#方法前面加上一个下划线,编程伪私有
            #时间返回的是一个元组形式,索引前六个分别是年月日时分秒
            self.arr=[]#按照年月日时分秒差值6单位个添加进去【持续时间】
            self.prompt="总共持续了:"
            for i in range(6):
                self.arr.append(self.end[i]-self.begin[i])
                #if self.arr[i]:#如果不是0
                    #self.prompt+=str(self.arr[i])+str(self.unit[i])
    
            #解决出现减出负号的问题
            arrlist=[5,4,3,2,1,0]
            arrlist1=['这个肯定不用',12,30,12,60,60]#30那个有的月份是31 2月也可能反正很多
            for i in arrlist:
                if self.arr[i]<0:
                    self.arr[i]+=arrlist1[i]
                    self.arr[i-1]-=1
            for i in range(0,6):
                if self.arr[i]:#如果不是0
                    self.prompt+=str(self.arr[i])+str(self.unit[i])
            print(self.prompt)
            #执行完归零方便下次调用
            self.begin=0
            self.end=0
            

    ·~~~属性访问~~~

     下放图,setattr这 写return也是一样的

    无论属性存不存在,获取属性第一个走的方法就是__getattribute__(),他必须有renturn,否则当该属性不存在的时候也不会执行__getattr__()方法

     

     下图这样写会进入死循环

     

    解决方案:

       或者这样写也可以:  .__dict__是把所有属性以字典的形式返回出来

         ~~~描述符(property的原理)~~~

     ·就是当我把这个特殊的类实例化赋给了另一个类的属性的时候,之后实例化那个类,操作那个属性的时候就操作我这个特殊类的__get__等方法

    self:指的是我这个特殊的类的实例,就是另一个类中赋予的那个属性

    instance:指的是另一个类的实例化

    owner:指的是指的是另一个类

                       

    下图中不是__del__而是__delete__  【__del__是被垃圾回收机制回收该块实例化占的内存的时候调用】

     

     

    下图中的self指的是该类的实例化fah,而不是那个类

     

      协议

    对于列表、元组、字典等等都是容器,那么接下来谈一谈容器的协议

     

     

     

     

    #用数组表示          #牢记可变参数*啊
    class List:
        def __init__(self,*arg):
            self.count=[0 for x in arg]#把前面0换成x这就是把arg每个参数都赋值给列表
            self.values=[]
            for i in arg:
                self.values.append(i)
        def __len__(self):
            return len(self.values)
        def __getitem__(self,key):
            self.count[key]+=1
            return self.values[key]
        def __delitem__(self,key):
            del self.count[key]
            del self.values[key]
    
    #用字典表示数量
    class CountList:
        def __init__(self,*args):
            self.values=[x for x in args]
            #他使用的是字典
            self.count={}.fromkeys(range(len(self.values)),0) #这种形式{0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
    
        def __len__(self):
            return len(self.values)
        def __getitem__(self,key):
            self.count[key]+=1
            return self.values[key]
        def __delitem__(self,key):
            del self.count[key]
            del self.values[key]
            self.countTemp={}.fromkeys(range(len(self.values)),0)
            for i in range(len(self.values)):
                if i<key:
                    self.countTemp[i]=self.count[i]
                else:
                    self.countTemp[i]=self.count[i+1]
            self.count=self.countTemp

    迭代器~~!!

      迭代:序列(列表 元组 字符串 字典)

    iter()生成迭代序列

    next()开始寻找下一个元素

    如果迭代全部完成next再次执行会抛出StopIteration的异常

    我们可以通过while写出for循环的原理

     

    那么关于迭代器的魔法方法有俩个,就是对应的前俩个BIF的实现

     

     本身就是迭代,因此在__iter__写的就是self  

     

  • 相关阅读:
    antd使用DatePicker组件出现TypeError: date.clone is not a function错误
    nrm解决npm install安装慢的问题
    antd pro显示自定义icon
    antd v4 使用后台返回的icon type的icon,并绑定事件
    复制textarea里输入的内容
    jsDelivr 缓存刷新小工具
    SweetAlert2网页弹窗---JAVASCRIPT弹窗
    Viewer.js 图片预览插件
    给你的网站加一个可爱的”躲猫猫“
    【Pyhton】随机漫步散点图
  • 原文地址:https://www.cnblogs.com/ningxinjie/p/10954169.html
Copyright © 2020-2023  润新知