day28

                                                     一.元类

1.使用背景

type(name,bases,dict)创建一个新的type类,类是由type类实例化产生的,而一个类由类名(str格式),基类(tuple格式)和名称空间(dict格式,key为str格式)三部分组成。

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

2.定义

用于产生类的类,通常在类名后加MetaClass.

3.应用场景

用于限制类,满足某些条件

具体来说,当我们需高度定制类时,如限制类必须大写时等,我们就需要使用元类,但元类type中代码无法被修改,只能创建新的元类(继承自type),通过覆盖__init__函数来完成对类的限制

①__init__函数

在实例化对象时会先产生空对象,类也是一种对象,所以创建类对象也会产生空的类对象,然后再执行__init__函数,并传入类的三个必要参数:类名,父类,名称空间

eg.

class MyMetaClass(type):

      # 元类中的self表示的都是类对象
     def __init__(self,class_name,bases,name_dict):

          # 不要忘记调用父类的初始化
   super().__init__(class_name,bases,name_dict)
   print(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():
      print("方法名称必须全小写 傻蛋!")
      raise Exception
  pass

 

②__new__函数

注:和__init__均是在创建类对象时执行,__new__先执行,产生类对象,再执行__init__来对元类进行限制,如果没有__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
    return type.__new__(cls,*args,**kwargs)

     # 如果覆盖__new__ 一定要写上这行代码

 

# 就算__init__中什么都不写, 这个类对象其实在__init__已经创建完成了, 该有的属性都有了,# 这是与普通类不同之处

class MyMetaClass(type):

  def __init__(self):

    pass

class Person(metaclass = MyMetaClass):

  pass

 

eg:

class DocMeatClass(type):

  def __init__(self,class_name,bases,name_dict):
    super().__init__(class_name,bases,name_dict)
      if not self.__doc__:
        raise Exception

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

 

③__call__函数

在调用类,实例化类对象时执行,控制对象的创建过程。

__call__也可用于自定义元类,在函数下的代码中进行属性的操作

eg:

class MyMeta(type):

  # 获得某个类的实例
  def __call__(self, *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)

 

                                         二.单例模式

一种设计模式,当需要的类仅有一个实例,即可使用。

通用方法:

 

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 Person(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)

 

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")
p2 = Person("jon snow",18,"man")

print(p1, p2)

print(p1.act())

print(p2.act())

 

stu1 = Student("布兰",16,"man")

stu2 = Student("布兰",16,"man")
stu3 = Student("布兰",16,"man")

print(stu1,stu2,stu3)

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

复习:当某个类的所有对象中只有个别特征和行为不同,我们可以将相同的特征行为放入类中,不同的特征和行为放进对象中。

当某一个类所有对象与其他类的所有对象间仅个别特征和行为不同,我们可以定义一个父类,然后将不同的特征和行为进行派生处理。

 

                                        三.异常

1.定义

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

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

2.目的

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

3.分类

①语法检测异常

②运行时异常

4.组成

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

最后一行 前面是错误的类型
后面时错误的详细信息

在查找错误时 主要参考的就是详细信息

5.语法

语法1
try:
print("start")
{"name":1}["xxx"]
print("over")
except:
print("key 不存在!")

 

语法2 在except中指定要处理的异常类型

try:
print("start")
{"name":1}["xxx"]
1[:]
print("over")
except KeyError:
print("出问题了")

 

语法3 在except中可以指定多种异常类型 使用统一的处理方案 没啥用

try:
print("start")
{"name":1}["xxx"]
1[:]
print("over")
except (KeyError,TypeError):
 print("出问题了")

 

语法4 一个try可以跟多个except 语句 每个处理不同的异常
try:

print("start")
 {"name":1}["xxx"]
1[:]
print("over")
except KeyError:
print("key不存在!!!!!")
except TypeError:
print("要操作的类型不对啊!!")

 

语法5 万能异常 尽量少用 因为 无法知道具体原因
try:
print("start")
{"name":1}["xxx"]
1[:]
name
print("over")
except Exception:
print("不知道啥原因 反正有问题!")

 

语法6 给异常对象取别名 从而访问一异常对象
之所以 能处理任何类型 是因为 Exception 是所有异常类的父类
try:
print("start")
{"name":1}["xxx"]
1[:]
name
print("over")
except Exception as e:
print("有问题! 原因为%s" % e)
print(type(e))

 

最常用的方式 在处理异常时 一定要记得打印一下异常信息 否则 你的程序不会出问题 但是也不会正常运行

try:
name
except NameError as e:
print(e)

6.如何处理?

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

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

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

#自定义异常

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

class MyException(Exception):
  pass

#主动抛异常

 

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

 

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

 

 

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

 

assert

表示非常肯定某个条件是成立的。

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

 

posted @ 2019-05-24 21:26  呼吸决定丶  阅读(121)  评论(0)    收藏  举报