zoukankan      html  css  js  c++  java
  • 面向对象高级-反射/魔法方法/元类

    day25

    面向对象高级

    一、isinstance and issubclass:

    1、isinstance() 判断一个对象是不是一个类的实例化对象;

    2、issubclass 判断一个类是不是另一个类的子类。

    class People(object):
        pass
    class Student(People):
        pass
    ​
    stu = Student()
    isinstance() 判断一个对象是不是一个类的实例化对象
    print(isinstance(stu, Student))       #True
    print(isinstance(stu, People))        #True
    print(isinstance(stu, object))        #True
    print(isinstance(stu, int))           #False
    issubclass 判断一个类是不是另一个类的子类
    print(issubclass(Student, People))    #True

    二、反射

    1、什么是反射:程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

    2、反射提供的四种方法:

    a、hasattr 是否存在某个属性

    b、getattr 获取某个属性的值

    c、setattr 设置某个属性的值

    d、delattr 删除某个属性

    注:以上的四个方法都是通过字符串来操作属性

    class Student:
        def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex
    ​
        def study(self):
            print("学生正在学习...")
    ​
    stu = Student("egon","woman",38)
    # # print(stu.name)
    # stu.name = "gogon"
    # del stu.name
    # 当你获取到一个对象 但是并不清楚搞对象的内部细节时  就需要使用反射了
    def test(obj):
        if hasattr(obj,"name"):
            print(getattr(obj,"name","没有name属性"))
    ​
    test(stu)
    ​
    setattr(stu,"school","beijing")
    delattr(stu,"school")
    print(getattr(stu,"school","没有学校属性"))
    delattr(stu,"age")
    print(stu.age)
    ##反射练习##
    # class Student:
    #     def study(self):
    #         print("学习中....")
    #
    # stu = Student()
    # res = getattr(stu,"study",None)
    # print(res)
    # def eat(self):
    #     print("正在吃饭...")
    #
    # # 可以通过反射的方式为对象增加一个方法 但是注意 这样增加的方法就是一个普通函数 不会自动传值
    # setattr(stu,"eat",eat)
    #
    # print(getattr(stu,"eat",None))
    ​
    ​
    # 需要编写一个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)
        print(func)
        func()
    else:
        print("输入的指令不正确....")

    三、__ str__

    注:前后带__双下划线的都是特殊的内置函数,会在某些时候自动执行,一般情况下,我们不应该直接调用他们。

    __ str__的使用场景:当我们需要自定义打印显示内容时,使用该方法。他要求返回值必须是一个字符串,且会将其返回的字符串打印出来。

    class Test:
        def __init__(self,name):
            self.name = name
        def __str__(self):
            print("str run....")
            return self.name
    ​
    t = Test("安米")
    ​
    print(int(1).__str__())
    # print([1,2,3,5])
    # print(t)
    # 在讲一个对象转换字符串时  本质就是在调用这个对象 __str__方法
    print(str(t))

    四、__ del__析构函数

    当程序运行结束时,python解释器在清理内存时,会自动调用该方法。针对此特性,我们可以在此方法中加入一些Python解释器无法自动完成的清理操作,已达到释放内存的效果。


    # class Student:
    #
    #     def __del__(self):
    #         print("对象被删除了....")
    #
    # stu = Student()
    #
    # # 手动删除 立即执行__del__
    # del stu
    # import time
    # time.sleep(5)
    ​
    ​
    class TextFile:
    ​
        def __init__(self,filepath,mode="rt",encoding="utf-8"):
            self.file = open(filepath,mode=mode,encoding=encoding)
    ​
        def read(self):
            return self.file.read()
    ​
        def write(self,text):
            self.file.write(text)
    ​
        # 该方法其实就是一个通知性质 仅仅是告诉程序员 对象即将被删除
        def __del__(self):
            # 在这里关闭系统的文件 妥妥的
            self.file.close()
    ​
    tf = TextFile("2.今日内容.txt")
    print(tf.read())
    # tf.file.close() 不需要手动关闭了  在对象删除时会自动关闭
    tf.read()

     

    五、exec

    1、作用:帮助解析字符串形式的python代码,并且将得到的名称存储到指定的名称空间中,Python解释器的内部也是通过调用它来执行代码的。

    需要传入三个参数:

    参数一:需要一个字符串对象 表示需要被执行的python语句;

    参数二:是一个字典 表示全局名称空间;

    参数三:也是一个字典 表示局部名称空间。

    globalsdic = {}  #相当于是python内置域
    localsdic = {}   #相当于前面提到的全局域
    exec("""
    aaaaaaaaaaaaaaaaaaaa = 1
    bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2
    def func1():
        print("我是func1")
    """,globalsdic,localsdic)
    ​
    # 如果同时制定了 全局和局部 则 会字符串中包含名称 解析后存到局部中
    # print(globalsdic)
    print(localsdic)
    localsdic["func1"]()

    六、元类

    1、元类用于产生类的类,type就是元类,所有的自定义类都是通过type实例化得来的。

    2、类也是一个对象,可以通过使用type发现,类就是type类型的实例(对象),因此我们也可以自己调用type来实例化产生一个类。

    #通过调用type来实例化一个类
    classname = "student"
    student = type(classname, (object,),{})
    print(student)
    print(student.__dict__)
    p1 = student()
    ​
    class Test(object):  #Test = type("Test",(object,),{}) 等价
        pass

    总结:1、类是由type实例化产生的;

    2、我们可以使用type来实例化出来一个类;

    3、一个类是由类名字、类的父类元组和类的名称空间三个部分组成。


     

    七、__ call__

    在对象被调用时执行

    自定义元类的目的:

    1、可以通过__ call__来控制对象的创建过程:

    #用__call__来控制对象的创建过程
    class MyMeta(type):
        def __call__(self,*args,**kwargs):
            print("Meta call run!")
            obj = object.__new__(self)  #创建一个空对象
            self.__init__(obj,*args,**kwargs)  #调用初始化函数
            return obj           #得到一个完整的对象
    class People(metaclass = MyMeta):
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __call__(self):
            print("call run!")
    #调用Person这个对象时 执行的是 Person的类(MyMeta)中__call__ 方法
    p = Person("张三疯",80)
    print(p)
    # 当调用对象时 会执行该对象所属类中的__call__方法
    # p()    
    print(p.name)
    print(p.age)

    2、可以控制类的创建过程,(__ init__):

    class MyMeta(type):
        def __init__(self,class_name,bases,namespace):
            print(self.__dic__)
            if not class_name.istitle:
                raise TypeError("类名首字母必须大写。。")
            if not self.__doc__:
                raise TypeError("类中必须要有文档注释。。。")
    class Student(metaclass = MyMeta):
    """
        这是文档注释
    """
        def __init__(self,name,age):
            self.name = name
            self.age = age
     

    总结:

    1、控制类的创建过程:

    a、创建一个元类(需要继承type);

    b、覆盖__ init__方法,该方法会将新建的类对象,类名,父类元组,名称空间一同传入;

    c、对于需要被控制的类,需要在类名后面指定metaclass为上面的元类。

    2、控制类实例化对象的过程

    a、创建一个元类(需要继承type);

    b、覆盖__ call__方法,会将正在实例化对象的类、调用类时传入的参数一同传入;

    c、在__ call__方法中,必须要先编写模板代码;

    1、创建空对象; 2、调用类的__ init__方法来初始化这个空对象; 3、返回该对象。

    d、加入你需要控制的逻辑 。


     

    八、单例

    1、什么是单例:如果一个类只有一个实例,那么该类称之为单例

    # 单例的实现
    class MyMeta(type):
        obj = None
        def __call__(self, *args, **kwargs):
            if not MyMeta.obj:
                MyMeta.obj = object.__new__(self)
                self.__init__(MyMeta.obj, *args, **kwargs)
            return MyMeta.obj
    ​
    class Printer(metaclass=MyMeta):
        obj = None
        def __init__(self, name, brand, type):
            self.name = name
            self.brand = brand
            self.type = type
    ​
        @classmethod
        def get_printer(cls):
            if not cls.obj:
                cls.obj = cls("et202","aideli","2018")
            return cls.obj
    ​
    ​
        def printing(self):
            print("%s is printing!"%self.name)
    ​
    p = Printer.get_printer()
    print(p)
    p = Printer.get_printer()
    print(p)
    p = Printer.get_printer()
    print(p)
    ​
    p = Printer("et202","aideli","2018")
    print(p)
    ​
    #result:
    #<__main__.Printer object at 0x0000000002528E80>
    #<__main__.Printer object at 0x0000000002528E80>
    #<__main__.Printer object at 0x0000000002528E80>
    #<__main__.Printer object at 0x0000000002528E80>

     

  • 相关阅读:
    网络测量中基于Sketch方法的简单介绍
    Reading SBAR SDN flow-Based monitoring and Application Recognition
    Reading Meticulous Measurement of Control Packets in SDN
    Reading SketchVisor Robust Network Measurement for Sofeware Packet Processing
    ovs加dpdk在日志中查看更多运行细节的方法
    后缀数组
    (转载)LCA问题的Tarjan算法
    Codeforces Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) A. Checking the Calendar(水题)
    Vijos 1816统计数字(计数排序)
    卡特兰数
  • 原文地址:https://www.cnblogs.com/peng-zhao/p/10145402.html
Copyright © 2011-2022 走看看