博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
day29,元类,单例模式,异常处理
阅读量:4686 次
发布时间:2019-06-09

本文共 7806 字,大约阅读时间需要 26 分钟。

                                元类,单例模式,异常处理

元类

什么是元类

一切皆对象

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

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

类对象 是由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])) == "
": 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__并返回执行结果

class MyMetaClass(type):    def __init__(self,class_name,bases,name_dict):        # super().__init__(class_name,bases,name_dict)        print("init")        pass    # 该方法会在实例化类对象时自动调用并且在 init 之前调用    # 其作用时用于创建新的类对象的    # 注意这里必须调用type类中的__new__ 否则将无法产生类对象   并且返回其结果    def __new__(cls, *args, **kwargs):        # cls 表示元类自己 即MyMetaClass        # print("new")        # print(args,kwargs)        return type.__new__(cls,*args,**kwargs)  # 如果覆盖__new__ 一定要写上这行代码class Person(metaclass=MyMetaClass):    passprint(Person)# 就算__init__中什么都不写 这个类对象其实已经创建完成了 该有的属性都有了# 这是与普通类不同之处# print(Person.__name__)# class Student:#     def __init__(self,name):#         pass## s = Student("张三")## s.name

 

 

使用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

 元类实现单例模式:

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 objclass Person(metaclass=SingletonMetaClass): # Person = SingletonMetaClass("Person",(object,),{})    def __init__(self,name,age,gender):        self.name = name        self.age = age        self.gender = gender    def say(self):        print("my name is %s  my 姑姑 is 龙妈" % self.name)class Student(metaclass=SingletonMetaClass):    def __init__(self,name,age,gender):        self.name = name        self.age = age        self.gender = gender    def say(self):        print("my name is %s  my 姑姑 is 龙妈" % self.name)p1 = Person("jon snow",18,"man")# p1.say()p2 = Person("jon snow",18,"man")# # p1.say()# p3 = Person("jon snow",18,"man")# p1.say()# print(p1, p2)stu = Student("布兰",16,"man")print(p1 , stu)stu1 = Student("布兰",16,"man")stu2 = Student("布兰",16,"man")stu3 = Student("布兰",16,"man")
View Code

异常

 

什么是异常

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

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

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

 

异常的分类

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'      不存在这个keyFileNotFoundError: [Errno 2] No such file or directory: 'xxxxx'  文件找不到

 

 

异常的组成:

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

 

Traceback    是异常追踪信息   用于展示错误发生的具体位置 以及调用的过程其中 包括了 错误发生的模块  文件路径   行号  函数名称  具体的代码最后一行  前面是错误的类型  		 后面 错误的详细信息   在查找错误时 主要参考的就是详细信息

 

异常处理

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

如何正确处理异常

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

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

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

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

     

自定义异常类

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

继承自Exception即可

class  MyException(Exception):    pass

 

主动抛出异常:

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

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

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

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

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

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

 

断言assert

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

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

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

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

转载于:https://www.cnblogs.com/WBaiC1/p/10920417.html

你可能感兴趣的文章
SQL Server 2008 清空删除日志文件
查看>>
循环创建目录
查看>>
生成带logo的二维码
查看>>
不急着往前赶,先把一些经典的题重新做几遍
查看>>
[FZYZOJ 1249] 水果堆
查看>>
tomcat源码分析(三)一次http请求的旅行-从Socket说起
查看>>
基于Windows环境下的PHP开发环境搭建
查看>>
蓝桥--兰顿蚂蚁[模拟]
查看>>
字符串基本操作
查看>>
2-4 Sass的函数功能-颜色函数
查看>>
Spring学习第一天---Spring是什么
查看>>
Servlet容器理解(生命周期、servletContext作用域、servlet装载方式)
查看>>
vs2008 sp1补丁包 安装失败
查看>>
分页存储过程优化--同时返回数据总数
查看>>
关于APK签名的一些东西
查看>>
让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法
查看>>
innerHTML与innerText的区别
查看>>
git简单配置
查看>>
mvc-1
查看>>
Android 读取文件内容
查看>>