zoukankan      html  css  js  c++  java
  • 面向对象高级

    isinstance() 判断某个对象是不是某个类的实例

    issubclass() 是不是字类

    # 判断某个对象是不是某个类的实例
    # isinstance()
    
    class Person:
    #
        pass
    class Student(Person):
        pass
    
    stu = Student()
    
    #判断 两个对象是不是同一个类型
    print(type(1) == type(1))
    
    # 判断stu对象是不是Student类的实例
    print(isinstance(stu,Student))
    
    # 是不是子类
    # issubclass()
    
    # 判断一个类是不是 另一个类子类 (所有类都是object的子类或子子类)
    print(issubclass(Student,Person))
    反射  其实说的实反省
    简单的说 就是 对象要具备一种修正错误的能力

    hasattr 是否存在某个属性
    getattr 获取某个属性的值
    setattr 设置某个属性的值
    delattr 删除某个属性

    这几方法有一个共同点 都是通过字符串来操作属性
    你可以理解为 通过字符串来操作属性 就叫做反省
    class Student:
        def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex
    
        def study(self):
            print("学生正在学习...")
    
    
    stu = Student("矮根","woman",38)
    
    # # print(stu.name)
    #
    # stu.name = "高根"
    #
    # 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("输入的指令不正确....")
    View Code
    """
    
        __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))
    __str__
    """
        __del__
    
        当对象被从内存中删除时会自动执行
        另一种情况时  程序员手动删除了这个对象 也会自动执行
    
    
        什么时候使用它
        在python中 有自动内存管理机制 所以 python自己创建的数据 不需要我们做任何操作
        但是有一种情况 我们使用python打开了一个不属于python管理的数据
        比如打开了一个文件  这个文件一定是操作系统在打开 会占用系统内存  而python解释器无法操作系统内存的
        所以 当你的python解释器运行结束后  文件依然处于打开状态  这时候就需要使用__del__来关闭系统资源
    
        简单地说 当程序运行结束时 需要做一些清理操作 就使用__del__
    
        __del__也称之为 析构函数
    
        分析构造 并拆除这个对象
    
    
    
    
    
    """
    #
    # 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()
    __del__
    """
        exec
        execute的缩写
        表示执行的意思
    
        其作用 是帮你解析执行python代码 并且将得到的名称 存储到制定的名称空间  解释器内部也是调用它来执行代码的
    
    """
    # 参数一 需要一个字符串对象 表示需要被执行的python语句
    # 参数二 是一个字典 表示全局名称空间
    # 参数三 也是一个字典 表示局部名称空间
    
    globalsdic = {}
    localsdic = {}
    
    exec("""
    aaaaaaaaaaaaaaaaaaaa = 1
    bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2
    def func1():
        print("我是func1")
    """,globalsdic,localsdic)
    
    
    # 如果同时制定了 全局和局部 则 会字符串中包含名称 解析后存到局部中
    # print(globalsdic)
    print(localsdic)
    localsdic["func1"]()
    
    
    
    
    
    # # 如果只传了一个传参数 则 将字符串中包含名称 解析后存到全局中
    # exec("""
    # aaaaaaaaaaaaaaaaaaaa = 1
    # bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2
    #
    # """,localsdic)
    exec
    """
        一切皆对象
        元类是指 用于产生类的类  type就是元类
        所有的自定义类都是通过type实例化得来
    
    """
    
    #创建模块的过程 1.创建一个空的名称空间 2.执行内部的代码 3.将得到的名字放到名称空间中
    
    # class也是一个对象
    class Student(object):
    
        school = "北京大学!"
    
        def study(self):
            print("学习中...")
    
    
    
    # 使用type可以发现 类其实是type类型的实例(对象)
    print(type(Student))
    
    # 我们可以自己调用type来实例化产生一个类
    
    
    
    # myclass 包含的代码
    code = """
    name = "张三"
    age = 18
    def hello(self):
        print("hello %s" % self.name)
    """
    
    
    
    #类的名字
    class_name = "MyClass"
    #类的的父类们
    base_classes = (object,)
    #类的名称空间
    namespace = {}
    
    exec(code,{},namespace)
    
    
    res = type(class_name,base_classes,namespace)
    
    print(Student)
    print(res.name)
    print(res.age)
    print(res.hello)
    
    
    
    # 1.类是由type实例化产生的
    # 2.我们可以使用type来产生一个类
    # 3.一个类是由 类名字 类的父类元祖 类的名称空间 三个部分组成
    
    
    class Test(object): #Test = type("Test",(object,),{})
        pass
    元类type
    """
    
        __call__
    
        调用的意思
        在在对象被调用时 执行
    
        函数 类
    
    
        自定义元类 的目的
        1.可以通过__call__ 来控制对象的创建过程
        2.可用控制类的创建过程
    
    
    """
    
    # 自定义一个元类 元类也是一个类   但是需要继承type
    class MyMeta(type):
    
        # self 表示要创建对象的那个类(Person)  *args是调用Person类时传入的参数
        def __call__(self, *args, **kwargs):
    
            print("MyMte中的 call run'")
            print(self,*args,**kwargs)
    
            # 下面的三步是固定写法 一个模板 只要你需要控制对象的创建过程 就应该先把模板写出来
    
            # 1.创建空对象
            obj = object.__new__(self)
            # 2.调用初始化方法
            self.__init__(obj,*args,**kwargs)
            # self.__init__(obj)
            # 3.得到一个完整的对象
            return obj
    
    
    
    # 修改Person类的元类为MyMeta
    class Person(metaclass=MyMeta):
    
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def __call__(self, *args, **kwargs):
            print("call run...")
    
    
    #调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法
    p = Person("张三疯",80)
    
    print(p)
    # 当调用对象时 会执行该对象所属类中的__call__方法
    # p()
    
    print(p.name)
    print(p.age)
    
    
    # class People:
    #     def __init__(self,name):
    #         self.name = name
    #     pass
    #
    #
    # p = People()
    # p.anme = 1
    自定义元类控制对象实例化
    # 要控制类的创建过程 只要找到类所属的类 中的__init__即可
    
    
    class MyMeta(type):
    
        # self 刚建出来的类
        # 第二个 类的名字
        # 第三个 类的父类们 元组
        # 第四个 这个类传进来的名称空间
        def __init__(self,class_name,bases,namespace):
            print("============================")
            #print(self.__dict__)
            # 我要控制 类的名字  必须 是大写开头
            if not class_name.istitle():
                print("类名 必须大写开头...... ")
                # 该代码是主动抛出异常
                raise TypeError("类名 必须大写开头...... ")
            #要空类的创建 必须包含__doc__这个属性
            if not self.__doc__:
                raise TypeError("类中必须有文档注释.....")
    
            pass
    
    class Student(metaclass=MyMeta):   # Student = MyMeta("Student",(object,),{})
        """
            这是文档注释  可以通过__doc__来获取
            这是一个学生类
        """
    
        # 在类的__init__中可以控制该类对象的创建过程
        def __init__(self,name):
            print("-----------------------")
            print(self.__dict__)
            self.name = name
    
    print(Student.__doc__)
    
    # 元类使用总结:
    """
    元类是用于创建类的类
    学习元类是为了 能控制类的创建过程 以及 类实例化对象的过程
    一.
    控制类的创建过程
        1.创建一个元类 (需要继承type)
        2.覆盖__init__方法  该方法 会将新建的类对象  类名 父类们 名称空间 都传进来 ,
            可以利用这些信息在做处理
        3.对于需要被控制的类 需要指定metaclass 为上面的元类 
        
    二.
    控制类实例化对象的过程
         1.创建一个元类 (需要继承type)
         2.覆盖__call__方法 会将 正在实例化对象的类  调用类是传入的参数  都传进来
         3.在__call__方法中 必须要先编写模板代码
            3.1创建空对象
            3.2调用类的__init__方法来初始化这个空对象
            3.3返回该对象
         4.加入你需要控制的逻辑 
         
    类的三个组成部分
    类名 父类们 名称空间
    
    元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象
    
    
    """
    通过元类控制类的创建
    class MyMeta(type):
    
        obj = None
        def __call__(self, *args, **kwargs):
            if not self.obj:
                obj = object.__new__(self)
                self.__init__(obj,*args,**kwargs)
                self.obj = obj
            return self.obj
    
    
    #打印机类
    class  Printer(metaclass=MyMeta):
        """
        这是一个单例类 请不要直接实例化 使用get方法来获取实例
        """
    
        obj = None
        def __init__(self,name,brand,type):
            self.name = name
            self.brand = brand
            self.type = type
    
        def printing(self,text):
            print("正在打印 %s"  % text)
    
        # 通过该方法来获取对象 可以保证只有一个对象
        # 但是这还不够 因为 还是可以通过调用类产生新对象
        # 就应该使用元类 来控制实例化的过程 __call__
        # 在__call__ 中编写代码 保证每次调用call 都返回同一个实例 即可
    
    
    
    # 以下三个对象 的数据完全相同 但是却 占用三分内存空间
    # p1 = Printer("ES005","爱普生","彩色打印机")
    # p2 = Printer("ES005","爱普生","彩色打印机")
    # p3 = Printer("ES005","爱普生","彩色打印机")
    
    # 现在要处理问题就是  如何能够限制该类 只能实例化一个对象
    
    
    p1 = Printer("ES005","爱普生","彩色打印机")
    p2 = Printer("ES007","爱普生","彩色打印机")
    
    print(p1)
    print(p2.name)
    # print(p1,p2,p3)
    
    
    # p1.printing("一本小说....")
    单例模式
  • 相关阅读:
    JS开发框架DevExtreme v20.1.7上线
    Web开发:看如何定义Kendo UI Grid Width
    如何创建自定义DevExpress报表控件,看完你就懂了
    高性能HTML5/JavaScript开发框架DevExtreme全新发布v20.1.7|附下载
    WPF界面开发:如何将不同集合中的项目显示为同一父节点子项
    界面开发包DevExpress v20.1.7上线!即刻体验
    WPF界面开发2020:Scheduler等控件功能升级
    Winform界面开发看过来!一招教你使用属性网格自定义编辑器
    将从数据库查询出来的带有父子结构的list转换成treeList结构
    将JDBC ResultSet结果集转成List
  • 原文地址:https://www.cnblogs.com/BestSkye/p/10156021.html
Copyright © 2011-2022 走看看