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>

     

  • 相关阅读:
    <JavaScript> 组合继承
    <JavaScript> 稳妥构造函数模式与工厂模式的区别
    <JavaScript> call()、apply()、bind() 的用法
    <JavaScript>可枚举属性与不可枚举属性
    <JavaScript>闭包(closure)
    在MongoDB中实现聚合函数
    (转)如何入门 Python 爬虫
    Python爬虫实战四之抓取淘宝MM照片
    转载:十年驾车经验总结:活着,才是硬道理
    设计模式之单例模式的七种写法
  • 原文地址:https://www.cnblogs.com/peng-zhao/p/10145402.html
Copyright © 2011-2022 走看看