• 元类


    一.isinstance issubclass

    class Person:
      pass
    class Student(Person):
      pass
    stu1=Student()
    #判断是不是实例
    print(isinstance(stu1,Student))
    #判断是不是子类
    print(issubclass(Student,Person))

    二.反射

    反射 实际上就是反省
    简单来说就是 对象具有一种修正错误的能力
    hasatter 是否存在某个属性
    getatter 获取某个属性
    setatter 设置某个属性
    delatter 删除某个属性
    这几个方法有个共同点都是通过字符串来操作属性
    通过字符串来操作属性 ,这就是反省

    class Student:
      def __init__(self,name,sex,age):
        self.name=name
        self.sex=sex
        self.age=age
      def study(self):
        print('该学生正在学习')
    stu1=Student('henry','man',29)
    def test(obj):
      if hasattr(obj, 'name'):
        print(getattr(obj, 'name'))
      else:
        print('没有name这个属性')
    test(stu1)
    这个test方法可以直接由print(getattr(stu1,"name","没有name属性")) 替换

    setattr(stu1,'school','shandong')
    print(getattr(stu1,'school')) #结果:shandong
    delattr(stu1,'school')
    print(getattr(stu1,'school','没有school这个属性')) #结果:没有school这个属性

    什么时候用反射?
    如果在编写代码期间 就能明确知道我要访问的属性 没有必要使用反射
    如果在编写代码期间 无法明确知道我要访问的属性 这时就应该使用反射

    class Student:
      def study(self):
        print('正在学习中')
    stu=Student()
    res=getattr(stu,'study',None)
    print(res) #绑定的方法 bound method
    def eat():
      print('正在吃东西')
    setattr(stu,'eat',eat)
    print(getattr(stu,'eat',None)) #function
    可以通过反射的方式为对象增加一个方法 但是注意 这样增加的方法就是一个普通函数 不会自动传值

    需要编写一个CMD工具 这个工具可以支持两个命令 dir ,tasklist
    class CMD:
      def dir(self):
        print('查看当前文件夹目录')
      def tasklist(self):
        print('查看任务列表')
    cmd=CMD()
    res=input('请输入指令:').strip()
    if hasattr(cmd,res):
      func=getattr(cmd,res)
      func()
    else:
      print('输入指令有误')

    三.__str__ __del__
    前后带__的都是特殊的内置函数,会在某些时机自动执行,一般情况我们不应该直接调用它们

    当我们需要自定义打印现实内容时 就需要__str__方法
    该方法必须返回一个字符串
    class Test:
      def __init__(self,name):
        self.name=name
      def __str__(self):
        print('str run..')
    return self.name
    t=Test('henry')
    print(t)
    结果:str run..
      henry
    # 在讲一个对象转换字符串时 本质就是在调用这个对象 __str__方法
    print(str(t))

    __del__
    当对象被从内存中删除时会自动执行
    另一种情况时 程序员手动删除了这个对象 也会自动执行
    什么时候使用__del__
      在python中 有自动内存管理机制 所以 python自己创建的数据 不需要我们做任何操作
      但是有一种情况 我们使用python打开了一个不属于python管理的数据
      比如打开了一个文件 这个文件一定是操作系统在打开 会占用系统内存 而python解释器无法操作系统内存的
      所以 当你的python解释器运行结束后 文件依然处于打开状态 这时候就需要使用__del__来关闭系统资源
      简单地说 当程序运行结束时 需要做一些清理操作 就使用__del__
    __del__也称之为 析构函数
    分析构造 并拆除这个对象
    class Testfile:
      def __init__(self,filename,mode,encoding='utf-8'):
        self.file=open(filename,mode,encoding=encoding)
      def read(self):
        return self.file.read()
      def wtite(self,text):
        self.wtite(text)
      def __del__(self):#该方法其实就是一个通知性质,仅仅告诉程序员对象将被删除
        self.file.close() #在这里关闭文件
    tf=Testfile('E:python-li课堂day26测试文件','rt')
    print(tf.read())

    四.exec

    exec
    execute的缩写
    表示执行的意思
    作用:帮助解析执行的代码,并且将得到的名称存储到指定的名称空间 解释器的内部也是调用它来执行代码的
    三个参数:
    参数一:需要一个字符串对象,表示需要被执行的python语句
    参数二:是一个字典 表示全局名称空间
    参数三:也是一个字典 表示局部名称空间
    #如果同时制定了 全局和局部 则 会将字符串中包含名称 解析后存到局部中
    globalsdic={}
    localsdic={}
    exec('''
    aaaaaa=1
    bbbbb=1
    def func1():
      print('我是func1')
    ''',globalsdic,localsdic)
    print(localsdic)
    #结果:{'aaaaaa': 1, 'bbbbb': 1, 'func1': <function func1 at 0x000001FBA4AF1E18>}

    #如果只传了一个传参数 则 将字符串中包含名称 解析后存到全局中
    dic={}
    exec('''
    aaaaa=1
    bbbbb=1''',dic)
    print(dic)#输出的就是全局的

    exec中,放到第二个参数位置的字典不论名字是什么都表示全局名称空间,放到第三个位置的字典不论名字是什么都表示局部名称空间.

    五.元类

    1.什么是元类?
    一切皆对象
    class关键字自定义的类其实也是一个对象
    元类是指产生类的类 type就是元类
    所有的自定义的类都是通过type实例化得来的
    2.为何要用元类?
    为了控制类的产生过程,还可以控制对象的产生过程
    3.怎么用?
    创建元类方法有两种?
    方式一:用class关键字去创建,用的默认的元类type
    class Student:
      school='beijing'
      def __init__(self,name,age):
        self.name=name
        self.age=age
      def study(self):
        print('正在学习!')
    s1=Student('henry','23')
    print(type(s1))#结果:<class '__main__.Student'> s1的类是Student
    print(type(Student)) #结果:<class 'type'> Student的类是type,类其实是type类型的实例(对象)
    print(Student) #结果:<class '__main__.Student'>

    方式二:用自定义元类
    首先要明白创建类的三要素 类名,类的父类,类的名称空间
    类名:
    class_name='Student'
    类的父类也叫基类:
    class_bases=(object,) #其实是一个元组
    类的名称空间字典的形式:
    class_dic={}
    class_body='''
    school='beijing'
    def __init__(self,name,age):
      self.name=name
      self.age=age
    def study(self):
      print('正在学习!')
        '''
    exec(class_body,{},class_dic) #利用exec传入名称空间
    #准备好创建类的三要素
    print(class_name)
    print(class_bases)
    print(class_dic)
    #Student=type(类名,基类,类的名称空间)
    Student=type(class_name,class_bases,class_dic)
    print(Student) #<class '__main__.Student'>

    class Test(object): #Test = type("Test",(object,),{})
      pass

    自定义元类的目的
    目的一.自定义元类通过__call__方法控制类的调用过程及控制对象实例化过程
    __call__ :调用的意思,在对象被调用时执行

    class Mymeta(type):
      def __call__(self, *args, **kwargs):
        print('Mymeta中的call run')
        print(self) #<class '__main__.Student'>
        print(args) #('henry', 29)
        print(kwargs) #{}
    class Student(object,metaclass=Mymeta):
      def __init__(self,name,age):
        self.name=name
        self.age=age
      def study(self):
        print('正在学习!')
    obj=Student('henry',29)

    调用Student的目的:
    先创建一个Student的空对象
    为该空对象初始化所有的属性

    #自定义一个元类,需要继承type
    class Mymeta(type):
      #self 要创建对象的那个类(Student) *调用Student类时传入的参数
      def __call__(self, *args, **kwargs):
        #固定写法
        #创建一个空对象
        obj = self.__new__(self)
        #为空对象初始化独有的属性
        self.__init__(obj,*args,**kwargs)
        #返回一个初始好的对象,得到一个完整的对象
        return obj
    #修改Student的元类为Mymeta
    class Student(object,metaclass=Mymeta):
      def __init__(self,name,age):
        self.name=name
        self.age=age
      def study(self):
        print('正在学习!')
    #调用Student这个对象时 执行的是 Student的类(type)中__call__ 方法
    obj=Student('henry',29)

    print(obj.name)
    print(obj.age)
    obj.study()

    目的二:控制类的创建过程
    要控制类的创建过程 只要找到类所属的类 中的__init__即可
    class Mymeta(type):
      #self 刚建出来的类
      #第二个 类的名字
      #第三个 类的父类们 元组的形式
      #第四个 这个类传进来的名称空间
      def __init__(self,class_nane,bases,namespace):
        #控制类的名称必须大写
        if not class_nane.istitle():
          #该代码是主动抛出异常
          raise TypeError('类名开头必须大写')
        #控制刚建的类必须有__doc__这个属性
        if not self.__doc__:
          raise TypeError('类中必须由文档注释')

    class Student(object,metaclass=Mymeta):
      '''
      这是文档注释 可以通过__doc__来获取
      这是一个学生类
      '''
      def __init__(self,name,age):
        self.name=name
        self.age=age
      def study(self):
        print('正在学习!')

    元类使用总结:
    元类是用于创建类的类
    学习元类是为了 能控制类的创建过程 以及 类实例化对象的过程
    一.
    控制类的创建过程
      1.创建一个元类 (需要继承type)
      2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 ,
        可以利用这些信息在做处理
      3.对于需要被控制的类 需要指定metaclass 为上面的元类

    二.
    控制类实例化对象的过程
      1.创建一个元类 (需要继承type)
      2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来
      3.在__call__方法中 必须要先编写模板代码
        3.1创建空对象
        3.2调用类的__init__方法来初始化这个空对象
        3.3返回该对象
      4.加入你需要控制的逻辑

    类的三个组成部分
    类名 父类们 名称空间

    元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象

    六.单例

    单例:
    单例模式是一种设计模式
    单个实例
    一个类如果只有一个实例 那么这个类被称之为单例
    什么时候使用单例?
    当要处理的对象只有一份时或者当所有对象的属性都相同时

    打印机类:实现单例
    方法一:
    class Printer:
    '''
    这是一个单例,请不要直接实例化,由get方法来获取实例
    '''
      obj=None
      def __init__(self,name,brand,type):
        self.name=name
        self.brand=brand
        self.type=type
      def printing(self,test):
        print('正在打印%s'%test)
      @classmethod
      def get_printer(cls):
        if not cls.obj:
          cls.obj=cls('Es005','爱普生','彩色打印机')
          return cls.obj
        else:
          return cls.obj
    p=Printer.get_printer()
    print(p)
    '''
    通过上述方法来获取对象可以保证只有一个对象
    但是这还不够,因为我们仍然可以通过调用类来产生对象
    '''
    方法二:
    '''
    就应该使用元类 来控制实例化的过程 __call__
    在__call__ 中编写代码 保证每次调用call 都返回同一个实例 即可
    '''
    class Mymeta(type):
      obj=None
      def __call__(cls,*args,**kwargs):
        if not Mymeta.obj:
          obj=object.__new__(cls)
          cls.__init__(obj,*args,**kwargs)
          Mymeta.obj=obj
          return Mymeta.obj
        else:
          return Mymeta.obj
    class Printer(object,metaclass=Mymeta):
      def __init__(self,name,brand,type):
        self.name=name
        self.brand=brand
        self.type=type
      def printing(self,test):
        print('正在打印%s'%test)

    p1=Printer('傻子','服气','无聊')

    p2=Printer('你说','我不说','可怜')

    print(p1)

    print(p2)

    p1和p2内存地址相同

  • 相关阅读:
    iPhone 12 Pro 不锈钢边框刮伤 All In One
    .vscodeignore All In One
    程序员如何挑选和购买一款高性价比的电动升降桌 All In One
    TypeScript function arguments destructuring All In One
    LeetCode 旋转数组算法题解 All In One
    python 中实现DNA一致性序列计算
    python中输出两条长度一致序列碱基不同的个数
    python 中统计不同scafflod的GC含量并输出GC含量最高的scafflod
    python 中 斐波那契兔子问题
    python 中如何将列表中的数值转换为字符串
  • 原文地址:https://www.cnblogs.com/lizeqian1994/p/10158477.html
Copyright © 2020-2023  润新知