• python基础学习-day33==课后作业练习


    一、今日作业
    1.在元类中控制把自定义类的数据属性都变成大写
    cls_singleton.py模块
    class Foo(object):
        pass
    
    
    instance = Foo()
     
    class Mymetaclass(type):
        # Chinese, Chinese.__name__, (), {country:China, tag:..., walk函数名称:...}
        def __new__(cls, name, bases, attrs):
            # print(cls)
    
            update_attrs = {}
    
            for k, v in attrs.items():
                # callable(方法) 判断是否是可调用的函数或方法
                # 不是 方法 与 私有属性, 都将属性名改为大写
                if not callable(v) and not k.startswith('__'):
                    update_attrs[k.upper()] = v
    
                else:
                    update_attrs[k] = v
    
            return type.__new__(cls, name, bases, update_attrs)
    
    
    class Chinese(metaclass=Mymetaclass):  # Mymetaclass()
        country = 'China'
        tag = 'Legend of the Dragon'  # 龙的传人
    
        def walk(self):
            print('%s is walking' % self.name)
    # print('第一题:', Chinese.__dict__)
    2.在元类中控制自定义的类无需__init__方法
     1.元类帮其完成创建对象,以及初始化操作;
    
        2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
    
        3.key作为用户自定义类产生对象的属性,且所有属性变成大写
    
    class Mymetaclass(type):
    
        # 调用Chinese类时会触发该方法 self ---> Chinese
        def __call__(self, *args, **kwargs):
            # 判断如果传递进来的是位置参数,则抛出异常
            if args:
                raise TypeError('must use keyword argument for key function')
    
            # 创造一个空的对象
            obj = object.__new__(self)  # 创建对象,self为类Foo
    
            # **name='lili', age=18, sex='male'  ---> {name:'lili', age:18, sex:'male'}
            for k, v in kwargs.items():
                # k ---> name   , v ---> lili
                # 修改对象的名称空间中的属性
                obj.__dict__[k.upper()] = v
    
            # 将修改后的对象返回
            return obj
    
    
    class Chinese(metaclass=Mymetaclass):  # obj = Mymetaclass() ---> Chinese = obj
        country = 'China'
        tag = 'Legend of the Dragon'  # 龙的传人
    
        def walk(self):
            print('%s is walking' % self.name)
    
    
    # 默认继承object,内部会先自动触发 __new__ --> obj --->  接着去触发__init__(obj)
    p = Chinese(name='lili', age=18, sex='male')
    print(p.__dict__)
    3.在元类中控制自定义的类产生的对象相关的属性全部为隐藏属性
    class Mymeta(type):
    
        # 当自定义类,指向自定义元类时,会自动调用自定义元类中的__init__, 当前自定义元类没有,则找type类中的
        def __init__(self, class_name, class_bases, class_dic):
            # 控制类Foo的创建
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
            # super(Mymeta, self) - --> type
            # type.__init__(self, class_name, class_bases, class_dic)
    
        # 控制: 定义类时的创建过程
        # def __new__(cls, *args, **kwargs):
        #     pass
    
        # 控制调用类创建对象初始化的过程
        def __call__(self, *args, **kwargs):
            # args ---> 'lili', 18, 'male'
    
            # 1、控制Foo的调用过程,即Foo对象的产生过程
            obj = self.__new__(self)
    
            # 先调用Foo类中__init__方法,将空的对象与需要接收的参数一并传给类中的__init__
            # __init__(obj, 'lili', 18, 'male')
            self.__init__(obj, *args, **kwargs)
    
            # 已经初始化赋值完毕
            print(obj.__dict__)
            # 字典生成式
            # for k, v in obj.__dict__.items(): 遍历对象的名称空间 {'name': 'tank', ..}
            # '_%s__%s' % (self.__name__, k): 将公开的数据名 改为 为 _类名__属性名
            obj.__dict__ = {'_%s__%s' % (self.__name__, k): v for k, v in obj.__dict__.items()}
    
            return obj
    
    
    class Foo(object, metaclass=Mymeta):  # Foo = Mymeta(...)
        __a = None  # -> _Foo__a
        def __init__(self, name, age, sex):
            # self ---> obj.name = name
            self.name = name
            self.age = age
            self.sex = sex
    
        # @property
        # def get_name(self):
        #     return self.__name
    
    
    obj = Foo('lili', 18, 'male')
    
    # print('问题3:', obj.__dict__)
    # print(obj.name)  # 错误
    # print(obj._Foo__name)
    4.基于元类实现单例模式
    #5种单列模式
    '''
    单例模式:
        单例模式是一个软件的设计模式,为了保证一个类,无论调用多少次产生的实例对象,
        都是指向同一个内存地址,仅仅只有一个实例(对象)!
    
        五种单例:
            - 模块
            - 装饰器
            - 元类
            - __new__
            - 类方法: classmethod
    '''
    
    
    class People:
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
    # 调用三次相同的类,传递相同的参数,产生不同的三个实例
    p1 = People('tank', 17, 'male')
    p2 = People('tank', 17, 'male')
    p3 = People('tank', 17, 'male')
    # print(p1 is p2 is p3)
    
    # 打开同一个文件的时候,链接MySQL数据库
    ''' 伪代码
    mysql_obj1 = MySQL(ip, port)
    mysql_obj2 = MySQL(ip, port)
    mysql_obj3 = MySQL(ip, port)
    '''
    
    '''
    方式一: @classmethod  ---> 通过类方法来实现单例
    '''
    
    
    class Foo(object):
        # 定义了一个类的数据属性,
        # 用于接收对象的实例,判断对象的实例是否只有一个
        _instance = None  # obj1
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        @classmethod
        def singleton(cls, *args, **kwargs):
            # 判断类属性_instance是否有值,有代表已经有实例对象
            # 没有则代表没有实例对象,则调用object的__init__获取实例对象
            if not cls._instance:
                # object.__new__(cls): 创造对象
                # 没有参数情况下
                # cls._instance = object.__new__(cls, *args, **kwargs)
    
                # 有参数的情况下
                cls._instance = cls(*args, **kwargs)  # Foo()
    
            # 将已经产生的实例对象  直接返回
            return cls._instance
    
    
    obj1 = Foo.singleton('tank', '123')
    obj2 = Foo.singleton('tank', '123')
    # print(obj1 is obj2)
    
    '''
    方式二: 元类
    '''
    
    
    class MyMeta(type):
    
        # 1、先触发元类里面的__init__
        def __init__(self, name, base, attrs):  # self --> Goo
            # *** 造空的对象, 然后赋值给了Goo类中的_instance类属性
            self._instance = object.__new__(self)
            # 将类名、基类、类的名称空间,传给type里面的__init__
            super().__init__(name, base, attrs)
            # type.__init__(self, name, base, attrs)
    
        # 2、当调用Goo类时,等同于调用了由元类实例化的到的对象
        def __call__(self, *args, **kwargs):
            # 判断调用Goo时是否传参
            if args or kwargs:
                init_args = args
                init_kwargs = kwargs
    
                # 1)通过判断限制了用于传入的参数必须一致,然后返回同一个对象实例
                if init_args == args and init_kwargs == kwargs:
                    return self._instance
    
                # 2) 若不是同一个实例,则新建一个对象,产生新的内存地址
                obj = object.__new__(self)
                self.__init__(obj, *args, **kwargs)
                return obj
    
            return self._instance
    
    
    class Goo(metaclass=MyMeta):  # Goo = MyMeta(Goo)
        # _instance = obj
        def __init__(self, x):
            self.x = x
    
    
    g1 = Goo('1')
    g2 = Goo('1')
    # print(g1 is g2)  # True
    
    '''
    方式三: __new__实现   ---> 通过调用类方法实例化对象时,自动触发的__new__来实现单例
    '''
    
    
    class Aoo(object):
        _instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = object.__new__(cls)
    
            return cls._instance
    
    
    a1 = Aoo()
    a2 = Aoo()
    # print(a1 is a2)  # True
    
    '''
    方式四: 装饰器实现     ---> 通过调用类方法实例化对象时,自动触发的__new__来实现单例
    '''
    
    
    # 单例装饰器
    def singleton_wrapper(cls):  # cls ---> Too
        # 因为装饰器可以给多个类使用,所以这里采用字典
        # 以类作为key, 实例对象作为value值
        _instance = {
            # 伪代码: 'Too': Too的示例对象
        }
    
        def inner(*args, **kwargs):
            # 若当前装饰的类不在字典中,则实例化新类
            # 判断当前装饰的Too类是否在字典中
            if cls not in _instance:
                # obj = cls(*args, **kwargs)
                # return obj
                # 不在,则给字典添加 key为Too, value为Too()---> 实例对象
                # {Too: Too(*args, **kwargs)}
                _instance[cls] = cls(*args, **kwargs)
    
            # return 对应的实例对象cls(*args, **kwargs)
            return _instance[cls]
    
        return inner
    
    
    @singleton_wrapper  # singleton_wrapper(Too)
    class Too(object):
        pass
    
    
    t1 = Too()
    t2 = Too()
    # print(t1 is t2)  # True
    
    '''
    方式五: 模块导入实现
    '''
    import cls_singleton
    
    s1 = cls_singleton.instance
    s2 = cls_singleton.instance
    
    print(s1 is s2)  # True
  • 相关阅读:
    数据库三范式(转)
    Tyrion中文文档(含示例源码)
    mongodb数据库导入导出恢复
    HTTP协议:Content-Type
    requests爬虫组件
    JS 数组对象
    JS 函数
    javascript window对象属性和方法
    js String对象
    Math对象-JavaScript
  • 原文地址:https://www.cnblogs.com/dingbei/p/12706649.html
Copyright © 2020-2023  润新知