zoukankan      html  css  js  c++  java
  • 二十四、反射,元类和__call__方法,__new__方法,单例模式

    一、isinstance和issubclass

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象
    
    class Foo(object):
         pass
      
    obj = Foo()
      
    isinstance(obj, Foo)
    issubclass(sub, super)检查sub类是否是 super 类的派生类
    class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)

    二、反射

    反射:是用字符串类型的名字,去操作变量
    反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力 
    """反射:是用字符串类型的名字,去操作变量"""
    
    
    # name = 1
    # eval("print(name)")  # 1 容易出现安全隐患
    
    
    # 反射  就没有安全问题
    
    
    # 反射对象的属性和方法  hasattr getattr setattr delattr
    class A:
        price = 200
    
        def func(self):
            print("in func")
    
    
    a = A()
    a.name = "alex"
    a.age = 18
    # 反射对象的属性
    # ret = getattr(a, "name")  # alex 通过变量名的字符串形式取到的值
    # print(ret)  # alex
    # # 反射对象的方法
    # """里面是字符串,变成函数和对象的内存地址,加个()就可以调用方法"""
    # ret = getattr(a, "func")
    # print(ret)  # <bound method A.func of <__main__.A object at 0x00000299778143C8>>
    # ret()  # in func
    
    #
    # class A:
    #     price = 200
    #
    #     @classmethod
    #     def func(cls):
    #         print("in func")
    #
    #
    # # 反射类的属性
    # # A.price
    # ret = getattr(A, "price")
    # print(ret)  # 200
    # # 反射类的方法 classmethod 和staticmethod
    # # A.func()
    # if hasattr(A,"func"):  # 如果成立我就执行,不会报错
    #     ret = getattr(A, "func")()
    # ret() # in func
    
    # 反射模块的属性
    # print(res)
    # import my
    # #
    # # print(my.girl)
    # ret = getattr(my, "girl")
    # print(ret)
    #
    # # 反射模块的方法
    # my.eva()
    # if hasattr(my, "eva"):
    #     ret = getattr(my, "eva")()
    # print(ret)
    
    # 内置模块也能用
    import time
    
    # time.sleep()
    ret = getattr(time, "sleep")
    ret(2)
    
    import sys
    
    year = 2019
    print(sys.modules)  # '__main__': <module '__main__'
    print(sys.modules["__main__"].year)
    
    
    def eva():
        print("eva我喜欢听你讲课")
    
    
    # 反射自己模块中的变量
    getattr(sys.modules["__main__"], "year")
    
    # 反射自己模块中的方法
    if hasattr(sys.modules["__main__"], "eva"):
        getattr(sys.modules["__main__"], "eva")()
    
    name = input(">>>>>>>>>>:")
    print(getattr(sys.modules[__name__], "name"))
    
    
    # setattr 设置修改变量,没有就添加
    class A:
        pass
    
    
    a = A()
    setattr(a, "name", "nezha")
    setattr(A, "name", "eva")
    print(a.name)
    print(A.name)
    
    # delattr  删除
    delattr(a, "name")
    delattr(A, "name")
    # print(a.name)
    反射所有

    二、元类

    元类:创建类的类

    对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的(类就是元类的对象)

    定义类的规则都是从元类那来的

    默认情况下所有类的元类都是type,但是type是继承object

    创建类的三个要素;

    class Person(object):
        name =123
        pass
    
    #1.类名 (字符类型)2.类的父类或基类(元组或列表)3.类的名称空间(字典类型)

    1.type是继承object

    class Person:
        pass
    
    
    p = Person()
    print(type(p))  # <class '__main__.Person'>
    print(p.__class__)  # <class '__main__.Person'>
    print(type(Person))  # <class 'type'>  元类
    
    type()  #<class 'type'>

    2.只要继承了type 那么这个类就变成了一个元类

    """ 学习元类的目的:高度自定义一个类
        只要继承type,这个类就变成了元类
    需求:控制类的名字必须以“驼峰式”的方式来书写,否则报错"""
    
    
    # 定义元类
    class MyType(type):
        def __init__(self, clss_name, bases, dict):
            super().__init__(clss_name, bases, dict)  # 类的三要素:类名,基类(父类),类的名称空间
            print(clss_name, bases, dict)
            if not clss_name.istitle():
                raise Exception("名字不会写?类名要大写,sb")
    
    
    # 指定元类
    class Pig(metaclass=MyType):
        pass
    # 通过__init__方法控制类名(类的属性)
    # MyType("pig", (), {})  初始化方法

    三、__call__方法的应用

    1.自定义__call__方法

    class MyMeta(type):
        def __init__(self, name, bases, dict):
            super().__init__(name, bases, dict)
            print("你个铺盖仔")
    
        def __call__(self, *args, **kwargs):  # 可变参数爱传不传
            print("元类 call run")
            print(self)  # <class '__main__.Dog'>Dog类
            print(args)  # ()('大帅',)把对象属性传参传进来了
            print(kwargs)  # {}字典,传进来
            return super().__call__(*args, **kwargs)
    
    
    class Dog(metaclass=MyMeta):  # 会走元类init方法  Dog =MyMeta("Dog",(),{})
        def __init__(self, name):
            self.name = name
    
        def __call__(self, *args, **kwargs):
            print("call run")
    
    
    d = Dog("大帅")  # 类是元类的对象
    print(d.name)
    # 当你把类实例化会自动触发元类call方法,*args是位置传参列表元祖,*kwargs是字典"""

    2.需求把对象属性改为大写

    # 创建元类
    class MyType(type):
        def __call__(self, *args, **kwargs):
            new_args = []
            for i in args:
                new_args.append(i.upper())
    
            # print(new_args)
            print(kwargs)
            return super().__call__(*new_args, **kwargs)  # 执行或覆盖call方法
    
    
    class Person(metaclass=MyType):
        def __init__(self, name, gender):
            self.name = name
            self.gender = gender
    
    
    p = Person("wukai", "man")
    print(p.name, p.gender)  # WUKAI ,MAN
    # 调用自定义元类__call__方法可以修改对象属性
    # 注意自定义元类中,重点在于覆盖父类__call__方法,并返回其值
    class MyType(type):
        def __call__(self, *args, **kwargs):
           if args:
               raise Exception("顶你的费,不允许,用位置参数传参")
    
            # print(new_args)
           print(kwargs)
           return super().__call__(*args, **kwargs)  # 执行或覆盖call方法
    
    
    class Person(metaclass=MyType):
        def __init__(self, name, gender):
            self.name = name
            self.gender = gender
    
    
    p = Person(name="wukai",gender="man")
    p = Person("wukai", "man")
    print(p.name, p.gender)
    案列:不允许位置参数传参

    四、__new__方法

    当你要创建类对象时,会首先执行元类中__new__方法,先新创建“类对象”,然后自动调用__init__方法,对这个类进行初始化
    注意:new方法必须有返回值且必须是 对应的对象"
    # 自定义元类
    class Meta(type):
    
        def __new__(cls, *args, **kwargs):
            print(cls)  # 元类自己
            print(args)  # 创建类需要的几个参数:类名 基类 名称空间
            print(kwargs)  # 空字典
            print("run new")
            return super().__new__(cls, *args, **kwargs)  # 初始化类对象,必须有返回值且是类对象
            # obj=type.__new__(cls,*args,**kwargs)  # 第二种方法
            # return obj
    
        def __init__(self, a, b, c):
            super().__init__(a, b, c)
            print("run init")
    
    
    class A(metaclass=Meta):
        pass
    
    
    print(A)
    # 总结:new方法和init方法都可以实现控制类的创建过程,init更简单些
    # a = A()

    五、单例模式

    设计模式:用于解决某种固定问题的套路
    单例:指的是一个类只能产生一个对象
    单例目的:单例是为了节省资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象,浪费资源
     单例元类
    class Single(type):
        def __call__(self, *args, **kwargs):
            if hasattr(self, "obj"):
                return getattr(self, "obj")
            obj = super().__call__(*args, **kwargs)   # 初始化call方法
            print("new 了")
            self.obj = obj
            return obj
    
    
    class Student(metaclass=Single):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    stu = Student("jack", 18)
    stu = Student("jack", 18)
    stu = Student("jack", 18)
     

     

  • 相关阅读:
    反射自动填充model
    source control tool
    项目管理案例分析
    IOC
    js framework
    WPF 难点内容
    WPF MVVM
    NewSQL
    软件部门员工考核
    JavaScript 中级
  • 原文地址:https://www.cnblogs.com/wukai66/p/11310881.html
Copyright © 2011-2022 走看看