• day 28-1 元类、异常处理


    元类

    元类的用途:自定义元类控制类的创建行为及类的实例化行为

    Python 中一切皆为对象。

    一切接对象,对象可以怎么用呢?

    1、都可以被引用,x=obj

    2、都可以当作函数的参数传入

    3、都可以当作函数的返回值

    4、都可以当作容器类的元素,l=[func,time,obj,1]

    让我们先定义一个类,然后逐步分析

    class People:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s say welcome to here' % self.name)
    
    
    p = People('ysg', 21)
    p.say()
    print(type(p))              # <class '__main__.People'>
    print(type(People))         # <class 'type'>

    所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象t1是调用类OldboyTeacher得到的

    如果一切皆为对象,那么类 Peope 本质也是一个对象,既然所有的对象都是调用类得到的,那么 Peope 必然也是调用了一个类得到的,这个类称为元类

    总结:产生类的类称之为元类,默认使用 class 定义的类,他们的元类是 type。

    exec的用法

    参数1:字符串形式的命令

    参数2:全局作用域(字典形式),如果不指定默认就是用 globals()

    参数3:局部作用局(字典形式),如果不指定默认就是用 locals()

    例子

    g = {
        'x': 'ysg',
        'y': '123'
    }
    
    l = {}
    
    exec("""
    global x,m
    x = 'ysging'
    m = 'pei'
    z = '21'
    """, g, l)
    print(g)        # {'x': 'ysging', 'y': '123'..., 'm': 'pei'}
    print(l)        # {'z': '21'}

    元类定义的两种方式

    方法一:class

    class People:
        country = "China"
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def func(self):
            print('%s say good' % self.name)
    
    
    p = People('ysg', '22')
    print(People)                       # <class '__main__.People'>
    print(p, p.name, p.age)             # <__main__.People object at 0x0000020B0FC652E8> ysg 22

    方法二:type

    定义类的三要素:类名、类的基类、类的名称空间

    class_name = 'People'
    class_bases = (object,)
    class_body = """
    country = "China"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def func(self):
        print('%s say good' % self.name)
    """
    class_dic = {}
    exec(class_body, globals(), class_dic)
    People1 = type(class_name, class_bases, class_dic)
    print(People1)                      # <class '__main__.People'>
    p1 = People1('ysg', '22')
    print(p1, p1.name, p1.age)          # <__main__.People object at 0x0000020B0FC65470> ysg 22

    自定义元类控制类的创建行为

    实现检索类名称是否为大写,类中是否写入注释

    class Mymeta(type):
        def __init__(self, class_name, class_bases, class_dic):
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
            if not class_name.istitle():
                raise TypeError('类名称首字母要求大写')
    
            if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
                raise TypeError('新建的类必须标有注释')
    
    
    class People(object, metaclass=Mymeta):  # People = Mymeta(class_name,class_bases,class_dic)
        '''
            使用自定义元类控制类的创建行为
        '''
        country = "China"
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def func(self):
            print('%s say good' % self.name)

    自定义元类控制类的实例化行为

    预备知识 __call__

    class Foo:
        pass
    
    
    f = Foo()
    f()  # TypeError: 'Foo' object is not callable
    class Foo:
        def __call__(self, *args, **kwargs):
            print(self)
            print(args)
            print(kwargs)
    
    
    f = Foo()
    f(1, 2, 3, a=1, b=2, c=3)
    
    结果:
    <__main__.Foo object at 0x000001DBE6B7F240>
    (1, 2, 3)
    {'a': 1, 'b': 2, 'c': 3}

    由以上两个例子可以看出,在调用方式实际是自动调用了 __call__ 方法

    所以可以得出,在使用元类控制类的实例化行为时:

      元类内部也应该有一个 __call__ 方法,会在调用 Foo 时触发执行;Foo(1,2,x=1) 就相当于 Foo.__call__(Foo,1,2,x=1)

    例子:自定义元类控制类实现单实例

    预备知识:单实例

    单实例:对象内部特征如果一样的情况下,就不要产生新的内存空间,实现共用一个空间。

    非单实例:

    class Mysql:
        def __init__(self):
            self.host = '127.0.0.1'
            self.port = 3306
    
    
    m = Mysql()
    m1 = Mysql()
    print(m)  # <__main__.Mysql object at 0x000001517C67F278>
    print(m1)  # <__main__.Mysql object at 0x000001517C67F390>

    方法一:绑定方法实现单实例

    class Mysql:
        __singleins = None
    
        def __init__(self):
            self.host = '127.0.0.1'
            self.port = 3306
    
        @classmethod
        def si(cls):
            if not cls.__singleins:
                obj = cls()
                cls.__singleins = obj
            return cls.__singleins
    
    
    m = Mysql.si()
    m1 = Mysql.si()
    print(m)        # <__main__.Mysql object at 0x000001F1ECEC5278>
    print(m1)       # <__main__.Mysql object at 0x000001F1ECEC5278>

    方法二:元类实现单实例

    class Mymeta(type):
        def __init__(self, class_name, class_bases, class_dic):
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
            self.__singleins = None
    
        def __call__(self, *args, **kwargs):
            if not self.__singleins:
                obj = object.__new__(self)
                self.__init__(obj, *args, **kwargs)
                self.__singleins = obj
            return self.__singleins
    
    
    class Mysql(object, metaclass=Mymeta):
        def __init__(self):
            self.host = '127.0.0.1'
            self.port = 3306
    
    m = Mysql()
    m1 = Mysql()
    print(m)        # <__main__.Mysql object at 0x00000278E56552B0>
    print(m1)       # <__main__.Mysql object at 0x00000278E56552B0>

    异常处理

    什么是异常:异常是错误发生的信号,一旦程序出错,并且程序没有处理这个错误,就会抛出异常,并且程序的运行随之终止

      强调一:异常发生的条件如果是可预知的,此时应该用 if 判断预防异常

      强调二:异常发生的条件如果是不可预知的,此时应该使用异常处理机制,try...except

    错误分为两种:语法错误、逻辑错误

    例子:指定要预防的报错类型

    a = 'qwe'
    try:
        int(a)
    except ImportError:
        print('int 类型报错')
    
    结果:ValueError: invalid literal for int() with base 10: 'qwe'

    注意:当指定的类型和实际报错的类型不一致时,报错不会被预防,而是报出真实的报错信息

    a = 'qwe'
    try:
        int(a)
    except ValueError:
        print('int 类型报错')        # int 类型报错
        
    print('拦截报错信息后的输出')     # 拦截报错信息后的输出

    当类型一致时,会拦截报错,并执行下面的语句,不会打断程序的运行

    例子:异常的多分支

    用途:被检测的代码块存在抛出多种异常的可能性,即为每种异常指定单独的处理逻辑

    try:
        print('=====>1')
        a = 'qwe'
        int(a)
        print('=====>2')
        l = [1,2,3]
        l[100]
        print('=====>3')
        d = {}
        d['name']
        print('=====>')
    except ValueError as e:
        print('----->',e)           # -----> invalid literal for int() with base 10: 'qwe'
    except IndexError as e:
        print('----->', e)          # -----> list index out of range
    except KeyError as e:
        print('----->', e)          # -----> 'name'
    
    print('被检测代码块的代码')        # 被检测代码块的代码

    例子:万能异常处理——Exception

    用途:被检测的代码块存在抛出多种异常的可能性,且我们只为其设置一种处理逻辑

    try:
        print('=====>1')
        a = 'qwe'
        int(a)
        print('=====>2')
        l = [1,2,3]
        l[100]
        print('=====>3')
        d = {}
        d['name']
        print('=====>')
    except Exception as e:
        print('统一的处理方法----->', e)          # -----> invalid literal for int() with base 10: 'qwe'
    
    print('被检测代码块的代码')        # 被检测代码块的代码

    例子:else、finally

    try:
        print('=====>1')
        a = 'qwe'
        # int(a)
        print('=====>2')
        l = [1,2,3]
        # l[100]
        print('=====>3')
        d = {}
        # d['name']
        print('=====>')
    except Exception as e:
        print('----->', e)
    else:
        print('被检测代码块没有发生异常时执行')                # 被检测代码块没有发生异常时执行
    finally:
        print('不管被检测代码块没有发生异常时执行都执行')       # 无论被检测代码块是否发生异常时都执行

    finally 在回收资源时的运用

    不论是否发生异常都执行回收操作

    try:
        f = open('../test.txt', 'r', encoding='utf-8')
        print(next(f))
        print(next(f))
        print(next(f))
        print(next(f))
        print(next(f))
    finally:
        f.close()

     例子:主动触发异常——raise,异常类型(值)

    class Foo:
        def __init__(self,name,age):
            if not isinstance(name,str):
                raise TypeError('名称必须要使用 str 类型')
            self.name = name
            self.age = age
    
    
    f = Foo(123,12)

    例子:自定义异常类型

    class MyException(Exception):
        def __init__(self, msg):
            super(MyException, self).__init__()
            self.msg = msg
    
        def __str__(self):
            return self.msg
    
    
    raise MyException('自定义异常类')  # raise 包含 print(obj)
    结果:__main__.MyException: 自定义异常类

    例子:断言——assert

    info = {}
    info['name'] = 'ysg'
    # info['age'] = 22
    
    # 这一部分的判断 就叫做断言
    # if 'name' not in info:
    #     raise KeyError('name 的 key 不存在')
    # if 'age' not in info:
    #     raise KeyError('age 的 key 不存在')
    
    # 使用 assert
    assert ('name' in info) and ('age' in info)     # AssertionError
    
    if info['name'] == 'ysg' and info['age'] > 10:
        print('welcome')
  • 相关阅读:
    Hashmap实现原理
    策略模式
    Google Drive ubuntu
    numix Docky
    Google Drive 和 Dropbox 同步同一个文件夹目录
    sublime text 2
    matlab cell
    liteide
    taglist and nerdtree
    codeblocks
  • 原文地址:https://www.cnblogs.com/ysging/p/12074338.html
Copyright © 2020-2023  润新知