zoukankan      html  css  js  c++  java
  • 网络基础——元类,单例模式,属性查找

    一、 元类(***)难点

    定义类,控制对象产生

    定义元类,控制类产生(看源码时用)

    一切源自于一句话:python中一切皆为对象
    1、元类介绍
     对象是调用类得到
    元类是调用元类得到
    查看类(就是类型):type(obj)===>OldboyTeacher
    查看元类(就是类型):type(OldboyTeacher)==>type
    # 元类=》OldboyTeacher类=》obj
    class OldboyTeacher(object):
        school = 'oldboy'
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s says welcome to the oldboy to learn Python' % self.name)
    
    
    obj = OldboyTeacher('egon', 18)  # 调用OldboyTeacher类=》对象obj
    #                                  调用元类=》OldboyTeacher类
    
    # print(type(obj))
    print(type(OldboyTeacher))
    # 结论:默认的元类是type,默认情况下我们用class关键字定义的类都是由type产生的

    2、class关键字底层的做了哪些事造出来类? 

    一定是调用了type得到返回值,把返回值赋值给class关键字

    # 1、先拿到一个类名
    class_name = "OldboyTeacher"
    
    # 2、然后拿到类的父类
    class_bases = (object,)
    
    # 3、再运行类体代码,将产生的名字放到名称空间中
    class_dic = {}
    class_body = """
    school = 'oldboy'
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def say(self):
        print('%s says welcome to the oldboy to learn Python' % self.name)
    """
    exec(class_body,{},class_dic)
    # print(class_dic)
    
    # 4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名OldboyTeacher,oldboyTeacher就是我们用class自定义的那个类
    OldboyTeacher = type(class_name,class_bases,class_dic)

    3、自定义元类

    只有继承了type类的类才是自定义的元类
    type是内置的元类,type内部一定有个__init__用法
    class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
        pass
    
    
    class OldboyTeacher(object, metaclass=Mymeta):
        school = 'oldboy'
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s says welcome to the oldboy to learn Python' % self.name)
    
    
    # 1、先拿到一个类名:"OldboyTeacher"
    # 2、然后拿到类的父类:(object,)
    # 3、再运行类体代码,将产生的名字放到名称空间中{...}
    # 4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名OldboyTeacher,oldboyTeacher就是我们用class自定义的那个类
    OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...})

     4、自定义元类来控制OldboyTeacher类的产生

    import re
    
    class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
        def __init__(self, class_name, class_bases, class_dic):
            # print(self)  # 类<class '__main__.OldboyTeacher'>
            # print(class_name)
            # print(class_bases)
            # print(class_dic)
    
            if not re.match("[A-Z]", class_name):
                raise BaseException("类名必须用驼峰体")
    
            if len(class_bases) == 0:
                raise BaseException("至少继承一个父类")
    
            # print("文档注释:",class_dic.get('__doc__'))
            doc=class_dic.get('__doc__')
    
            if not (doc and len(doc.strip()) > 0):
                raise BaseException("必须要有文件注释,并且注释内容不为空")
    
    # OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...})
    class OldboyTeacher(object,metaclass=Mymeta):
        """
        adsaf
        """
    
        school = 'oldboy'
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s says welcome to the oldboy to learn Python' % self.name)

    5、自定义元类来控制OldboyTeacher类的调用

    自定义元类的目的是:定义规范

    这里涉及到如何隐藏属性问题:其实就是利用字典的k:v(此例子中有)

    import re
    
    class Mymeta(type):  # 只有继承了type类的类才是自定义的元类
        def __init__(self, class_name, class_bases, class_dic):
            # print(self)  # 类<class '__main__.OldboyTeacher'>
            # print(class_name)
            # print(class_bases)
            # print(class_dic)
    
            if not re.match("[A-Z]", class_name):
                raise BaseException("类名必须用驼峰体")
    
            if len(class_bases) == 0:
                raise BaseException("至少继承一个父类")
    
            # print("文档注释:",class_dic.get('__doc__'))
            doc = class_dic.get('__doc__')
    
            if not (doc and len(doc.strip()) > 0):
                raise BaseException("必须要有文件注释,并且注释内容不为空")
    
        # res = OldboyTeacher('egon',18)
        def __call__(self, *args, **kwargs):
            # 1、先创建一个老师的空对象
            tea_obj = object.__new__(self)
            # 2、调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
            self.__init__(tea_obj, *args, **kwargs)
            tea_obj.__dict__ = {"_%s__%s" %(self.__name__,k): v for k, v in tea_obj.__dict__.items()}
    
            # 3、将初始化好的老师对象赋值给变量名res
            return tea_obj
    
    
    # OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...})
    class OldboyTeacher(object, metaclass=Mymeta):
        """
        adsaf
        """
    
        school = 'oldboy'
    
        #            tea_obj,'egon',18
        def __init__(self, name, age):
            self.name = name  # tea_obj.name='egon'
            self.age = age  # tea_obj.age=18
    
        def say(self):
            print('%s says welcome to the oldboy to learn Python' % self.name)
    
    
    res = OldboyTeacher('egon', 18)
    print(res.__dict__)
    # print(res.name)
    # print(res.age)
    # print(res.say)
    
    # 调用OldboyTeacher类做的事情:
    # 1、先创建一个老师的空对象
    # 2、调用老师类内的__init__方法,然后将老师的空对象连同括号内的参数的参数一同传给__init__
    # 3、将初始化好的老师对象赋值给变量名res

    6、仅供理解的例子

    class Foo:
        def __call__(self, *args, **kwargs):
            print('================>')
            print(self)
            print(args)
            print(kwargs)
    
    
    obj1 = Foo()
    obj1(1,2,3,a=1,b=2)  # 调用对象其实就是在调用对象类中定义的绑定方法__call__
    #
    # obj2 = int(10)
    # obj2()
    
    # obj3 = list([1, 2, 3])
    # obj3()


    二、 单例模式

    字面意思:变成单个实例化的类

    目的:节省内存空间

    设计模式的一种

    三种方式实现单例模式

    IP='192.1.1.1'
    PORT=3306
    settings
    1、实现方式1:classmethod
    import settings
    
    class MySQL:
        __instance = None
    
        def __init__(self, ip, port):
            self.ip = ip
            self.port = port
    
        @classmethod
        def singleton(cls):
            if cls.__instance:
                return cls.__instance
            cls.__instance = cls(settings.IP, settings.PORT)
            return cls.__instance
    
    
    # obj1=MySQL("1.1.1.1",3306)
    # obj2=MySQL("1.1.1.2",3306)
    # print(obj1)
    # print(obj2)
    
    
    obj3 = MySQL.singleton()
    print(obj3)
    
    obj4 = MySQL.singleton()
    print(obj4)

    2、实现方式2:元类

    import settings
    
    class Mymeta(type):
        __instance = None
        def __init__(self,class_name,class_bases,class_dic):
            self.__instance=object.__new__(self)  # Mysql类的对象
            self.__init__(self.__instance,settings.IP,settings.PORT)
    
        def __call__(self, *args, **kwargs):
            if args or kwargs:
                obj = object.__new__(self)
                self.__init__(obj, *args, **kwargs)
                return obj
            else:
                return self.__instance
    
    # MySQL=Mymeta(...)
    class MySQL(metaclass=Mymeta):
        def __init__(self, ip, port):
            self.ip = ip
            self.port = port
    
    
    # obj1 = MySQL("1.1.1.1", 3306)
    # obj2 = MySQL("1.1.1.2", 3306)
    # print(obj1)
    # print(obj2)
    
    obj3 = MySQL()
    obj4 = MySQL()
    
    print(obj3 is obj4)

    3、实现方式3:装饰器

    import settings
    
    def outter(func):  # func = MySQl类的内存地址
        _instance = func(settings.IP,settings.PORT)
        def wrapper(*args,**kwargs):
            if args or kwargs:
                res=func(*args,**kwargs)
                return res
            else:
                return _instance
        return wrapper
    
    @outter  # MySQL=outter(MySQl类的内存地址)  # MySQL=》wrapper
    class MySQL:
        def __init__(self, ip, port):
            self.ip = ip
            self.port = port
    
    
    # obj1 = MySQL("1.1.1.1", 3306)
    # obj2 = MySQL("1.1.1.2", 3306)
    # print(obj1)
    # print(obj2)
    
    obj3 = MySQL()
    obj4 = MySQL()
    print(obj3 is obj4)

    三、属性查找

    按照之前的查找顺序

    在有元类的情况下的属性查找顺序:一直找到父类找到object后再找元类

    class Mymeta(type):
        n=444
    
        # def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'>
        #     obj=self.__new__(self)
        #     print(self.__new__ is object.__new__) #True
    
    
    class Bar(object):
        # n=333
    
        # def __new__(cls, *args, **kwargs):
        #     print('Bar.__new__')
        pass
    
    class Foo(Bar):
        # n=222
    
        # def __new__(cls, *args, **kwargs):
        #     print('Foo.__new__')
        pass
    
    class OldboyTeacher(Foo,metaclass=Mymeta):
        # n=111
    
        school='oldboy'
    
        def __init__(self,name,age):
            # self.n=0
            self.name=name
            self.age=age
    
        def say(self):
            print('%s says welcome to the oldboy to learn Python' %self.name)
    
    
        # def __new__(cls, *args, **kwargs):
        #     print('OldboyTeacher.__new__')
    
    
    # obj=OldboyTeacher('egon',18)
    # print(obj.n)
    
    print(OldboyTeacher.n)
    ---34---
  • 相关阅读:
    uva 11178 Morley&#39;s Theorem(计算几何-点和直线)
    .net web 开发平台- 表单设计器 一(web版)
    Oracle EBS Web ADI 中的术语
    Android学习笔记(十七)——使用意图调用内置应用程序
    PreferenceFragment 使用 小结
    ccMacros
    海量数据查询优化
    c++容器类
    Codeforce 424C Magic Formulas 找规律
    android播放html5视频,仅仅有声音没有图像视频
  • 原文地址:https://www.cnblogs.com/guojieying/p/13521480.html
Copyright © 2011-2022 走看看