zoukankan      html  css  js  c++  java
  • 第二十六章 oop中元类、异常处理

    1、元类

      什么是元类:

      一切皆对象,类也是对象,可以把一个类当成普通对象来使用,比如存储到列表中或者作为参数传给函数等等....

      对象是如何产生的? 通过类实例化产生的

      类对象 是由 type 实例化产生的

      class AClass:
        pass
      print(type(AClass))

      我们可以手动调用 type 来实例化产生一个类;

      类的三个组成部分:

      1. 类的名称      我是谁

      2. 类的父类们    我从哪来

      3. 类的名称空间    我有什么(名称空间里存了什么) 

      type(类名,父类元组,名称空间)   #将会返回一个新的类

      type(对象)       # 将会返回这个对象的类型

       当定义一个class时解释器会自动调用 type 来完成类的实例化

      #模拟解释器创建类对象:

      def test1(a):
        print(a)

      def test2(self,b):
        print(self,b)

      class_name = "C"
      bases = (object,)
      name_dict = {"name":"jack","test1":test1,"test2":test2}

      C = type(class_name,bases,name_dict)
      # print(C)
      c1 = C()
      # print(c1)
      c1.test2(100)

      补充exec与eval:

      ***exec 用与执行字符串形式的 python 代码,只要符合 python 都能执行,并且可以指定将执行产生的名字放如某个名称空间 

      ***eval 用于执行简单的表达式,不饿能有任何的特殊语法

      class_text = 
      class A:
        def test(self):
          print(self)

      loca2 = {}
      exec(class_text,None,loca2)
      print(loca2)
      #eval(class_text) #报错

      元类:用于产生类的类,称之为元类

      元类 :metaclass 只要看见它就要想起来这是元类

      定义元类时,尽量在类名后添加MetaClass 方便阅读

      元类的作用(用来做什么)

      当我们需要高度定制类时,如限制类名必须答谢开头....

      就需要使用元类,但是元类 type 中的代码 无法被修改,只能创建新的元类(继承自 type)通过覆盖__init__来完成对垒起的限制

      元类的使用

      如何定义元类:

      class MyMetaClass(type):
        pass

      # 使用自定义元类
      class Person(metaclass=MyMetaClass):
        pass

      __init__方法(*****)

      实力化对象时会自动执行类中的__init__方法,类也是对象在实列化类对象时会自动执行元类中的__init__方法

      并且会传入类的三个必要参数,类的名字,分类们,名称空间

      当然会自动传入类对象本身作为第一个参数

    案例: 限制类名必须首字母大写 控制类中方法名必须全部小写

    class MyMetaClass(type):
       def __init__(self,class_name,bases,name_dict):

           super().__init__(class_name,bases,name_dict)
           # 类名必须首字母大写 否则直接抛出异常
           if not class_name.istitle():
               print("类名必须大写 傻x!")
               raise Exception

           # 控制类中方法名必须全部小写
           for k in name_dict:
               if str(type(name_dict[k])) == "<class 'function'>":
                   if not k.islower():
                       raise Exception
       pass

    # 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们 名称空间
    class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{})
       NAME = 10
       def say(self):
           print("SAY")
       pass

       __new__方法(***)

      元类中的new方法会在创建类对象时执行,并且先于 init 方法

       作用是创建一个类对象

      class A(metaclass=MyMetaClass):

        pass

      1.执行MyMetaClass的__new__方法 拿到一个类对象

      2.执行MyMetaClass的__init__ 方法 传入类对象以及其他的属性,进行初始化

      注意:如果覆盖了__new__一定也要调用 type 中的__new__并返回执行结果

      使用new方法也可以完成定制类的工作 和init有什么区别?

      在调用 init 方法前类对象已经创建完成了

      所以如果对性能要求高的场景,可以选择在new中完成定制,如果发现有问题,就不用创建类对象了

      

    需求: 要求每个类必须包含__doc__属性

    class DocMeatClass(type):

       def __init__(self,class_name,bases,name_dict):
           super().__init__(class_name,bases,name_dict)
           # if not("__doc__" in name_dict and name_dict["__doc__"]):
           #     raise Exception
           
           # 或者如下
           if not self.__doc__:
               raise Exception

    class Person(metaclass=DocMeatClass):
       """"""
       pass
      

      需求: 要求每个类必须包含__doc__属性 __doc__ 用于访问一个对象的注释信息


      # 你要控制类的创建 那就自定义元类 覆盖__init__
      class DocMeatClass(type):

      def __init__(self,class_name,bases,name_dict):
        super().__init__(class_name,bases,name_dict)
        # if not("__doc__" in name_dict and name_dict["__doc__"]):
          # raise Exception
        if not self.__doc__:
          raise Exception

      class Person(metaclass=DocMeatClass):
        pass

    __call__方法(*****)
    元类中的 call 方法会在调用类时执行
    可以用于控制对象的创建过程

    class MyMeta(type):

    # 获得某个类的实例
    def __call__(self, *args, **kwargs):
    print("call")
    # return super().__call__(*args,**kwargs)
    new_args = []
    for i in args:
    if isinstance(i,str):
    new_args.append(i.upper())
    else:
    new_args.append(i)
    return super().__call__(*new_args,**kwargs)

      # 注意注意注意: __new__ __init__ 是创建类对象时还会执行
      # __call__ 类对象要产生实例时执行

      class Student(metaclass=MyMeta):
        def __init__(self,name,gender,age):
        self.name = name
        self.gender = gender
        self.age = age

      s = Student("jack","woman",18)
      print(s.age)
      print(s.gender)


    class Person(metaclass=MyMeta):
      def __init__(self,name,gender):
        self.name = name
        self.gender = gender

      p = Person("rose","man")
      print(p.name)

      总结:当你要定制类时,就要地综艺元类并覆盖__init__ 方法

      元类实现单利模式

      什么是单利:

        莫各类如果只有一个实列化对象,那么该类成为单例类

      单例的好处:

        当某个类的所有对象特征和行为完全一样时,避免重复创建对象,浪费资源

      案例:  

      class SingletonMetaClass(type):
        #创建类时会执init 在这为每个类设置一个obj属性 默认为None
      def __init__(self,a,b,c):
        super().__init__(a,b,c)
        self.obj = None

      # 当类要创建对象时会执行 该方法
      def __call__(self, *args, **kwargs):
        # 判断这个类 如果已经有实例了就直接返回 从而实现单例
        if self.obj:
          return self.obj

    # 没有则创建新的实例并保存到类中
        obj = type.__call__(self,*args,**kwargs)
         self.obj = obj
         return obj

    2、异常

      什么是异常

      异常是程序运行过程中繁盛的非正常情况,是一个错误发生时的信号

      异常如果没有被正确处理的话,将导致程序被终止,这对于用户体验是非常差的,可能导致严重搞得后果

      处理异常的目的就是提高程序的健壮性

      异常的分类 

      python解释器在执行代码前会先检查语法,语法检查通过才会开始执行代码

      1.语法检测异常 作为一个合格的程序员 是不应该出现这种低级错误

      2.运行时异常

      已经通过语法检测,开始执行代码,执行过程中发生异常 称之为运行时异常

      异常:

    TypeError: 'int' object is not subscriptable     对象不能被切片  
    TypeError: 'list' object is not callable 对象不能被调用
    IndexError: list index out of range 索引超出范围
    TypeError: 'builtin_function_or_method' object is not iterable     对象不能被迭代
    KeyError: 'xxx'      不存在这个key
    FileNotFoundError: [Errno 2] No such file or directory: 'xxxxx'  文件找不到

      异常的组成:  

      Traceback (most recent call last):
      File "F:/python8期/课堂内容/day29/11.常见异常.py", line 22, in <module>
      with open("xxxxx") as f:
      FileNotFoundError: [Errno 2] No such file or directory: 'xxxxx'

      Traceback 是异常追踪信息 用于展示错误发生的具体位置 以及调用的过程
      其中 包括了 错误发生的模块 文件路径 行号 函数名称 具体的代码

      最后一行 前面是错误的类型
      后面 错误的详细信息 在查找错误时 主要参考的就是详细信息

      异常处理

      异常发生后 如果不正确处理将导致程序终止,我们必须应该尽量的避免这种情况发生

      

      重点:

      必须掌握的语法

      语法:

      try:

        可能会出现异常的代码 放到try里面

      except 具体异常类型 as e:

        如果真的发生异常就执行except

      

    如何正确处理异常

    1. 当发生异常 不是立马加try 要先找出错误原因并解决它

    2. try 仅在 即使你知道为什么发生错误 ,但是你却无法避免 例如 你明确告诉用户 需要一个正确文件路径 然而用户依然传入了错误的路径

      如 socket 双方都要使用管道 ,但是如果一方有由于某些原因强行关闭了 ,即使你知道原因也无法避免出错 那就只能try 保证程序正常结束

      总结一句话:能不加try 就不加try

      自定义异常类

      当系统提供异常类不能准确描述错误原因时 就可以自定义异常类

      继承自Exception即可

      class  MyException(Exception):
         pass
      

    主动抛出异常:

    什么时候需要主动抛出异常

    当我们做功能的提供者,给外界提供一个功能接口

    但是使用者不按照相应的方式来使用,或者参数类型不正确等原因,导致功能无法正常执行时,就应该主动抛出异常

    主动抛出异常使用raise 关键字

    后面可以跟任何Exception的子类 或是 对象

    raise MyException
    raise MyException("错误具体原因!")

     

    断言assert

    断言 其实可以理解为断定的意思

    即非常肯定某个条件是成立的

    条件是否成立其实可以使用if来判断

    其存在的目的就是 为了简化if 判断而生的

     

     
  • 相关阅读:
    MT9v024总结
    常用芯片电路知识汇总
    octopress 如何添加youku视频和本地视频(octopress how to add a youku video or a local video)
    MT9M021/MT9M031总结
    TC358746AXBG/748XBG 桥接器说明
    mipi 调试经验
    1‘b0 什么意思
    MIPI总结和MIPI规格说明书
    octopress添加回到顶部按钮
    CentOS软件安装目录查找
  • 原文地址:https://www.cnblogs.com/sry622/p/10919830.html
Copyright © 2011-2022 走看看