zoukankan      html  css  js  c++  java
  • 面向对象高级进阶

      一、反射

      定义:通俗的理解其实反省,自省的意思

              反射值的时一个对象具备在增 删  改 查 得的属性你能力

      操作方法:通过操作字符串操作属性 

      反射:设计的四个函数:hasattr ,get attr, setattr , delattr  者四个 函数就是普通内置函数,没有双下划线,就像print,sort,len()  区别于__getattr__  函数操作


    # 使用场景:
    # 反射其实就是对属性增删改查,如果直接使用内置dict,太过于繁琐,不好理解
    # 反射是框架的基石,为什么


    1.1 实列一:
    class Person:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    
    p = Person("Sen", 18)
    
    if hasattr(p, 'name'):
        # print(getattr(p,'name'))
        setattr(p, 'id', 123)  # 注意setattr 设置值的时候是有三个值的(对象,‘key’ ,value)
        print(p.id)
        # delattr(p, 'id')  # ttributeError: 'Person' object has no attribute 'id'
        # print(p.id)  # 此时‘id’已被删除
      print(p, 'id') 此时是不会取到对象的值的

    1.2 案例二:默认Djiang中间件 实现对象 的调用

    前戏:

    # 使用场景:
        # 反射其实就是对属性增删改查,如果直接使用内置dict,太过于繁琐,不好理解
        # 反射是框架的基石,为什么因位框架设计者补课不可能提前知道你的对象到底是怎么
        # 设计的所以你提供给框架的对象 必须通过判断验证之后才能正常使用
        # 判断就是反射要做的事情,当然也可以通过__dict__也可以实现的,其实这些方法也就对__dict__的操作进行了封装
    
    
    # 需求:要实现一个用于处理用户的终端指令的小框架
    # 框架:已经实现了最基础的架构代码逻辑,就是所有项目都是一样的部分
    # 框架 的根据配置 文件拿到所需的类
    class WinCmd:
        def cd(self):
            print('windcmd 切换目录。。。' )
    
        def delete(self):
            print('windcmd ..。删库')
    
        def dir(self):
            print('wind 列出当前的所有文件')
    
    
    class LinCmd:
        def cd(self):
            print('lindcmd 切换目录。。。' )
    
        def rm(self):
            print('lindcmd ..。删库')
    
        def ls(self):
            print('lincmd  列出所有文件')

    通过模块导入对象 实列化 调用

    # 导入刚才的库
    from day24.lib import my_work
    
    
    def run(my_work):
        while True:
            cmd = input('输入指令')
            if cmd == 'exit':
                break
            if hasattr(my_work,cmd):
                func = getattr(my_work,cmd)
                func() #
    
            else:
                print('不支持')
        print('再见!!!')
    
    
    wind = my_work.WinCmd()
    run(wind)

    很明显上述中我们的设计框架中写死必须用某个类,这是不合理的 以为我们无法提前预知对方的类在什么地方以及类名 所以我们应该为框架的使用者提供一个配置文件,要求对方将类写入文件 然后框架自己可以加载需要的模块

     实现代码:

      二、元类


    """该文件为框架的配置文件"""
    # 作为框架的使用者,在配置文件中指定你配合框架的类是哪个

    CLASS_PATH = 'lib.my_work.WinCmd'
    # 导入刚才的库
    import importlib
    
    from day24.lib import my_work
    from day24 import settings
    
    def run(my_work):
        while True:
            cmd = input('输入指令')
            if cmd == 'exit':
                break
            if hasattr(my_work,cmd):
                func = getattr(my_work,cmd)
                func() #
    
            else:
                print('不支持')
        print('再见!!!')
    # 创建一个插件对象 调用库框架来使用
    # wind = my_work.WinCmd()
    # run(wind)
    # 很明显这种实现不是完全的合理

    # 所以需要 根据文件拿到需要的类
    path = settings.CLASS_PATH


    # 从配中单独拿出来 模块路径 和 类名称
    print(path.rsplit('.',1)) # ['lib.my_work', 'WinCmd'] 者按照点切割的列表解压赋值
    module_path, class_name = path.rsplit('.', 1)

    # res = path.rsplit('.',1)
    print(class_name)
    # 拿到模块
    mk = importlib.import_module(module_path)
    print(mk) # <module 'lib.my_work' from 'D:\datas\day24\lib\my_work.py'>
    print(class_name)
    # 拿到类
    cls = getattr(mk,class_name)
    print(cls)
    obj = cls()

    # 调用框架
    run(obj) 实现代码 调
     obj 也就是这个类的实列对象class WinCmd  
    """
    在框架设计中 我们不可能提前知道 框架的用户要提供类相关的信息
    """
    import importlib
    import abc
    
    # 拿到模块 根据模块的路径
    pl = importlib.import_module("libs.plugins")
    print(pl)
    # 从模块中取出类
    cls = getattr(pl,"WinCMD")
    print(cls)
    
    
    # 实例化产生对象
    obj = cls()
    obj.cd()

    二、元类

      2.1 定义:什么元类:用于创建类的类,万物皆对象,类也是对象(类对象)对象是通过 类实列化产生,类对象也是另一个了实例化产生的

           默认情况下所有类的元类都是type  类的类是type

      

    # type 可以自定义类 拦截的类的产生
    
    # 我们的需求是创建类对象做一些限制
    # 实现方法一 既然是创建想到了初识化方法 我们只要找到类对象的类(元类)
    # 覆盖init 方法就能实现需求
    
    # 只要继承type类 那么这个类就变成了一个元类
    # 自定义类 first

    实现代码:

    lass MyClass(type):  # 元类
        # 拦截在父类产生Student 初始化走 的__init__
        def __init__(self,class_name,bases,dict):  # self Student 类对象、
            print(self)  # 类 对象 <class '__main__.Student'>
            print(class_name)  # 类名
            print(bases)
            print(dict)
            super().__init__(class_name, bases, dict)  # 重写父类放入方法
            if not class_name.istitle():  # 限制类的产生过程 必需满足我们限制的条件
                raise Exception('大哥不能呐必需是首字母大写')
            else:
                print('创建类成功')

    我们要自定义的类

    class Student(metaclass=MyClass):  # 自定义这个类怎么 重新type
       def __init__(self,name,age,b):
           self.name = name
           self.age = age
           self.b = b
    
    a = Student('KOKO',(1,2),b=1)  # 实列化
    #  __new__
    print(a.__dict__)  # {'name': 'KOKO', 'age': (1, 2), 'ui': {}}

      方法二其实就是内部本质先走元类自己的__new__ 1.元类中构建类再  返回类对象

    # 默认继承type 的类称为元类
    
    # 类的创建第二种方法__new__
    
    # __new__是帮我们创建类对象的初始化进行添加限制
    class Myself(type):  # 继承type >>>元类
        def __new__(cls, *args, **kwargs):
            # cls 是Myself
            # 方法一
            # return super().__new__(cls,*args,**kwargs)  # 必需返回给__init 生成相应的类,并返回
            # 方法二
            obj = type.__new__(cls, *args, **kwargs)  # 在元类中该函数用来构建类本身
            return obj  # 返回一个对象  给__init__  # 在类中,该函数用来构建类实例
    
        def __init__(self, a, b, c):
            super().__init__(a, b, c)
            print('实列创建类')
    
    
    class Teacher(metaclass=Myself):  # 限制老师类的产生
        pass
       属性
    
    Teacher()

    分为两个阶段:
    1.类的生成:由元类生成;
    2.实例的生成:由上述生成的类接着生成。

    具体描述:

    结合上一篇文章中,我们总结出生成一个类实例的全部过程:
    1.类首先查找内部__metaclass__属性是否被自定义元类赋值,若赋值则准备用该自定义元类生成类,否则用type作为元类生成类;
    2.解释器调用该元类的__new__函数(该函数为静态函数),并将要实例化的类中定义的各种属性传递给该函数固定的四个参数:其中cls是该元类本身,name是要被实例化的类的类名,bases是该类父类组成的元组,attrs则是该类{属性名:属性值,函数名:函数对象}组成的字典。
    3.最终通过type类生成该类,并返回。
    4.该类生成后,调用类中的__new__函数(该函数是静态函数)创建该类的实例,并返回该实例;
    5.该实例接着调用它的__init__函数初始化实例,这样一个完整的实例就被生成出来了。

    5,自定义元类的核心
    由于是元类构建了类,因此若要更改某些固定类(str,int等)的用法,就必须在元类中做文章了。而元类的核心是__new__函数,自然在该函数内做文章。比如可以通过atrris字典为元类添加新的属性和函数,或改变以往的属性或函数等。这样的改变会传播到所有用该元类创建的类中。

    总结:
    __new__函数:
    1.在元类中该函数用来构建类本身;
    2.在类中,该函数用来构建类实例;
    ---------------------
       元类中__call__  

    当你调用类对象时会自动触发元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数

    覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建
    并返回其返回值

    使用场景:

    当你想要控制对象的创建过程时,就覆盖call方法  对象创建过程__call__

    当你想要控制类的创建过程时,就覆盖init方法     控制类的创建  __init__

    案例:



    # 元类中的__call__方法 在对象加括号 会自动触发类中的__call__ 方法
    # 覆盖父类的__call__ 这个类无法差生对象 必须调用super().__call__
    # 来完成对象的创建,并返回其返回值



    #实现将对象的所有属性名称转为大写
    # 实现一

    class Mytype(type):
    # 控制对象的产生
    def __call__(self, *args, **kwargs):
    if args:
    raise Exception('不能用位置参数')
    return super().__call__(*args,**kwargs) # 必须返回这个对象



    class Person(metaclass=Mytype):
    def __init__(self,name,age):
    self.name =name
    self.age =age


    a = Person(name='jcsk',age=19)

    print(a.name)
    print(a.age)

     

     

     

    单列的实现

    class Single(type):
    def __call__(self, *args, **kwargs):
    print(self) # Student 类
    if hasattr(self, 'obj'):
    return getattr(self, 'obj')

    obj = super().__call__(*args, **kwargs) # 没有则有创建
    print(obj) # 实例化的对象
    print('新开的试试看看')
    self.obj = obj # 并保存到self 对象自己的名称空间中
    return obj


    class Student(metaclass=Single):
    def __init__(self, name, age):
    self.name = name
    self.age = age


    a = Student('jj', 12) #
    Student('mm', 12)
    Student('kk', 12)
    Student('pp', 12)
    Student('tt', 12)
    
    
    # l = [2, 1, 3, 5]  # 冒泡算是遍历里里面的元素 由第一个和第二个做比较 如是:按大到小进行编排

    # 列表的个数
    #
    # 先比较 2,1 得到2 1 1 3 1 5
    # 第一圈 0 索引
    # >>> 元素比较元素次数 次数len-1 3

    # 第二圈 1 索引
    # 2 3 2 5 2和1已经再第一次拿到最小值了 不用再比较 比较元素次数 为2 len -1 -1
    # l2 = [3, 5, 2, 1]


    # 第三圈 2 索引
    # 3 5 3和2 再 第二圈已经比较过了

    # l3 = [5, 3, 2, 1]

    # 需求要用函数的方法实现 找关系
    s = [2, 3, 5, 1,10,309]
    for i in range(len(s) - 1): # 元素比较的次数 第一次 顾头不顾尾range(3) 0 1 2 三次比较
    # print(i) # 0 1 2 3 元素的索引下标
    for j in range(len(s) - 1 - i): # i相当于圈数的索引i =1 第二次 顾头不顾尾range(2) 0 1 三次比较
    if s[j] < s[j+1]:
    # 解压赋值
    s[j], s[j+1] = s[j+1], s[j]
    print(s)


    class Num:
    def __init__(self,name,age):
    self.age = name
    self.age = age
    def __str__(self):
    return self.age

    def __gt__(self, other):

    return self.age > other.age


    a1 = Num('json','48')
    a2 = Num('json','19')
    a3 = Num('json','26')

    排序的 ????
    stu = [a1.age, a2.age, a3.age]
    for i in range(len(stu)-1):
    for j in range(len(stu)-1-i):
    if stu[j]>stu[j+1]:
    stu[j],stu[j+1] = stu[j],stu[j+1]
    print(stu)


    单列2:
    # 利用__new__ 在创建对象的时后先走
    会帮我们构建以及返回一个对象
    
    # 对象给__init__ 对象进行初始赋值
    
    """
    # 利用__new__ 在创建对象的时后先走  >>>么有创建 有返回
    会帮我们构建以及返回一个对象
    
    # 对象给__init__ 对象进行初始赋值
    
    """
    
    
    class Mysql(object):  # 默认继承object
        _instance = None  # 可以定义变量
    
        def __init__(self, name):
            self.name = name
            print(self)
            print('run init')
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                print(cls)
                print('run _new_')
                cls._instance = object.__new__(cls)  # 如果没有 重写object 的__new__ 将对象存到名称空间
    
                print('1111')
            return cls._instance
    
    
    obj = Mysql('Jack')
    obj2 = Mysql('rose')
    # obj3 = Mysql('kk
    print(id(obj), id(obj2))
    # 2705130166368  2705130166368
    # <class '__main__.Mysql'>
    # run _new_  >>>先走
    # 1111
    # <__main__.Mysql object at 0x0000017048A5C240>
    # run init  >>>再走
    # <__main__.Mysql object at 0x0000017048A5C240>
    # run init  >>>一样的

    单列3基于元类:对象调用__call__   么有值 重写父类的__call__

    # 单列实现一 利用元类 既然是对象的产生 >>>__call__
    
    
    class MyClass(type):  # 继承type
        # 控制类的产生__call__ 覆盖父类的__call__ 对象调用走__call__ 方法
        def __call__(self, *args, **kwargs):
            if hasattr(self, 'obj'):
                return getattr(self, 'obj')
            # 没有创建重写父类的__call__
            obj = super().__call__(*args, **kwargs)
            # 将对象保存
            print('new=====')
            self.obj = obj
            return obj
    
    
    class Student(metaclass=MyClass):  # 继承MyClass 父类
    
       def __init__(self,name,age):
           self.name = name
           self.age = age
    
    
    a1 = Student('jack',18)
    a2 = Student('rose',20)
    a3 = Student('roe',20)
    a4 = Student('roye',20)
    print(a1)
    print(a2)
    print(a3)
    print(a4)
    # new=====  只走了一次 
    # <__main__.Student object at 0x0000024DBFC1D160>
    # <__main__.Student object at 0x0000024DBFC1D160>
    # <__main__.Student object at 0x0000024DBFC1D160>
    # <__main__.Student object at 0x0000024DBFC1D160>

    单列4:装饰器 实现

    def singleton(cls):
        # 该对象在类Mysql被装饰上singleton的时候就已经实例化完毕
        _instance = cls('127.0.0.1',3306)
        def inner(*args,**kwargs):
            # 判断是否传入参数,传入参数表示要实例化新的,不传表示用默认的
            if args or kwargs:
                obj = cls(*args,**kwargs)
                return obj
            return _instance
        return inner
    
    @singleton
    class Mysql:
        def __init__(self,ip,port):
            self.ip = ip
            self.port = port
    
    obj1 = Mysql()
    obj2 = Mysql()
    obj3 = Mysql()
    print(obj1,obj2,obj3)def singleton(cls):
        # 该对象在类Mysql被装饰上singleton的时候就已经实例化完毕
        _instance = cls('127.0.0.1',3306)
        def inner(*args,**kwargs):
            # 判断是否传入参数,传入参数表示要实例化新的,不传表示用默认的
            if args or kwargs:
                obj = cls(*args,**kwargs)
                return obj
            return _instance
        return inner
    
    @singleton
    class Mysql:
        def __init__(self,ip,port):
            self.ip = ip
            self.port = port
    
    obj1 = Mysql()
    obj2 = Mysql()
    obj3 = Mysql()
    print(obj1,obj2,obj3)

    单列5基于

    基于classmethod)

    class Mysql(object):
        _instance = None
    
        def __init__(self, ip, port):
            self.ip = ip
            self.port = port
    
        @classmethod
        def singleton(cls):
            if not cls._instance:
                cls._instance = Mysql('127.0.0.1', 3306)
            return cls._instance
    
    
    obj1 = Mysql.singleton()
    obj2 = Mysql.singleton()
    print(obj1)
    print(obj2)
    单列6:
    # 单独在一个py文件中定义一个类,并实例化一个对象,之后在其他文件导入这一对象,实现单例
    # 单独在一个py文件中定义一个类,并实例化一个对象,之后在其他文件导入这一对象,实现单例
    class Singleton(object):
        def __init__(self,host,port):
            self.host = host
            self.port = port
    
    singleton = Singleton('127.0.0.1',3306)


  • 相关阅读:
    对MVC模型的自悟,详尽解释,为了更多非计算机人员可以理解
    openSUSE leap 42.3 实现有线 无线同时用
    Fedora27 源配置
    Ubuntu16.04添加HP Laserjet Pro M128fn打印机和驱动
    openSUSE leap 42.3 添加HP Laserjet Pro M128fn打印机和驱动
    OpenSUSE Leap 42.3下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    OpenSUSE Leap 42.3 安装java(Oracle jre)
    linux下支持托盘的邮件客户端Sylpheed
    Ubuntu下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    Firefox 浏览器添加Linux jre插件
  • 原文地址:https://www.cnblogs.com/mofujin/p/11272117.html
Copyright © 2011-2022 走看看