zoukankan      html  css  js  c++  java
  • python29 1.元类 2. 异常

    今日内容:

    1.元类

    2.异常

     

     Python:一门动态语言

    最大特点:运行期间动态生成类,修改对象属性

    详解:

    1.元类:

    1.1什么是元类?

    一切皆对象

           类也是对象,可以把一个类当作普通对象对象来使用,(对象怎么用,类就怎么用)

    使用:

           例如,存储到列表中,或者作为参数传给函数等等

    对象是如何产生的?

           通过实例化产生的

    类对象:

           是由type实例化产生的

    案例:

    class Aclass:

        pass

    print(type(Aclass))

    #值<class 'type'>

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

    一个类由三部分组成:

       1.类的名称    我是谁

       2.类的父类们   我从哪里来

       3.类的名称空间   我有什么

    type的两种使用方法:

    .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)
    #值:产生一个新的类<class '__main__.c'>
    c1=c()
    print(c1)
    #值:<__main__.c object at 0x00000256F4337A90>
    c1.test2(100)

    #值:<__main__.c object at 0x000002405D6A7A90> 100

    1.2补充:解释器执行代码的时候就是exec

        exec(执行)与eval(评价)

       glob全局名称空间   locl局部名称空间

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

     eval用于执行简单的表达式,(加减,基础运算)不能有任何的特殊语法

    class_test="""
    class A:
    def test(self):
    print(self)
    """#字符串形式的Python代码
    loca2={}
    exec(class_test,None,loca2)
    #print(loca2)
    #值{'A': <class '__main__.A'>}
    eval(class_test)#语法错误

    1.3元类(Type)(元类继承自object):用于产生类的类,称之为元类

    元类翻译为:

                metaclass 只要看见他就应该想起来这就是元类

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

     

    1.4(应用)用来干啥?(三种方法:__init__,__new__,__call__)

      当我们需要高度定制类的时候,如限制类名必须大写开头等等。。。。

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

     

     

     

    使用元类

    如何自定义元类:

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

    1.4.1__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("类名必须大写")
    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):
    pass

    1.4.2__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__ (文档的缩写)用于访问一个对象的注释信息
    # 需求: 要求每个类必须包含__doc__属性   __doc__ 用于访问一个对象的注释信息
    # class A:
    # """
    # this is a Class
    # author is jerry
    # """
    # pass
    # print(A.__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

     

    1.4.3__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方法

     

    1.5元类实现单例模式

     

    什么是单例:

     

    某个类如果只有一个实例对象,那么该类成为单例类

     

    单例的好处:

     

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

     

    案例:

     

    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.异常
    详解
     

    2.1什么是异常

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

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

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

     

    2.2异常的分类

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

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

    2.运行时异常  

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

     

    2.3异常:

    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'  文件找不到

     

    2.4异常的组成:

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

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

     

    2.5异常处理

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

    重点:

    必须掌握的语法

    语法:

    try:

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

    except 具体异常类型 as e:

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

    如何正确处理异常

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

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

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

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

       

    2.6自定义异常类

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

    继承自Exception即可

    class  MyException(Exception):
       pass

     

    主动抛出异常:

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

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

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

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

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

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

     

    断言assert

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

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

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

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

     

     

     

     

     

     

     

     

     

     

    优先掌握的内容:

    1.元类中的三个方法的执行时机以及使用场景

    2.单例模式

    3.异常处理语法

     

    4.要注重提升解决bug能力

     

     

     

     

     

     

     

     

     

     

     

    有什么用

    如何处理

     

     

     

    什么是元类 

    有什么用?

    1.控制类的创建过程

    2.控制对象的实例化过程

    如何控制

    控制类的创建过程  使用__init

    控制对象的实例化过程 使用 call  也需要调用type的call 并返回其结果    

    __new  会先于__init执行 在__new中必须 调用type的__new  并返回结果

     

     

     

     

    
    
    




  • 相关阅读:
    ZOJ 2671 Cryptography(线段树+求区间矩阵乘积)
    HDU 4662 MU Puzzle(找规律)
    Codeforces 392 C Unfair Poll(模拟)
    UVA 11134 Fabled Rooks(传说中的车)(贪心)
    UVA 11212 Editing a Book(IDA*算法+状态空间搜索)
    用户的昵称【哈希】
    【洛谷P2375】动物园【KMP】
    【洛谷P2375】动物园【KMP】
    【洛谷P2375】动物园【KMP】
    【洛谷P1886】滑动窗口【单调队列】
  • 原文地址:https://www.cnblogs.com/llx--20190411/p/10919745.html
Copyright © 2011-2022 走看看