元类+内置方法+反射

内容概要

  • 元类
  • 内置方法
  • 反射

内容详细

  • 元类

    # 一、什么是元类:
    # 元类就是用来实例化产生类的类
    # 元类-->实例化-->类(People)-->实例化-->对象(obj)
    class People:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s:%s'%(self.name,self.age))
    
    # 如何得到对象
    # obj = 调用类()
    # obj = People('ycc',18)
    # print(type(obj))  # <class '__main__.People'>
    
    # 如果说类也是对象
    # Peopel = 调用类()
    # People= People()
    
    # 查看内置的元类:
    # type是内置的元类
    # 我们用class关键字定义的所有的类以及内置的类都是元类type实例化产生
    
    # print(type(People))  # <class 'type'>
    # print(type(int))  # <class 'type'>
    
    # 二:class关键字创造People的步骤
    
    # 肯定有一步调了内置的元类加括号,然后传了一系列参数,实例化对象,赋值给People
    # People = type(...)
    
    # 类有三大特征:
    # 1、类名
    class_name = 'People'
    # 2、类的基类
    class_bases = (object,)
    # 3、执行类体代码拿到类的名称空间(对应的就是类的字典)
    class_dic = {}
    # 要做一件事:把下面字符串中的代码运行一下,然后把运行过程中产生的名字都能丢到上面的字典里去
    class_body= '''
    def __init__(self,name,age):
        self.name = name
        self.age = age
    
    def say(self):
        print('%s:%s'%(self.name,self.age))
    '''
    # 如何做这件事:
    exec(class_body,{},class_dic)
    
    # 4.调用元类
    People = type(class_name,class_bases,class_dic)
    print(People)  # <class '__main__.People'>
    
    # 三、如何自定义元类来控制类的产生
    class Mymeta(type):  # 只有继承了type类的类才是元类
        def __init__(self,class_name,class_bases,class_dic):
            print('run...')
            print(class_name)
            print(class_bases)
            print(class_dic)
            if not class_name.istitle():
                raise NameError('类名的首字母必须大写啊!!!')
        # 造空对象
        # cls: 当前所在的类 *args, **kwargs:调用类时所传入的参数
        def __new__(cls, *args, **kwargs):  # 早于__init__
            # 造Mymeta对象
            # print('run33333333')
            # print(cls,args,kwargs)
            return type.__new__(cls,*args,**kwargs)
    # People = Mymeta('People',(object),{...})
    # mymeta调的时候会将 'People',(object),{...} 这三个参数先传给new,new基于cls做一个造空对象的操作
    # 然后将cls传给上面的self,将*args,**kwargs传给class_name,class_bases,class_dic
    # 调用Mymeta发生三件事
    # 1、先造一个空对象=>People,调用类内的__new__方法
    # 2、调用Mymeta这个类内的__init__方法,完成初始化对象的操作
    # 3、返回初始化好的对象
    
    class People(metaclass=Mymeta):
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def say(self):
            print('%s %s'%(self.name,self.age))
    
    # 强调
    # 只要是调用类,那么会依次调用
    # 1、类内的__new__
    # 2、类内的__init__
    
  • 内置方法

    # 1、什么是内置方法
    # 定义在类内部,以__开头并以__结尾的方法
    # 特点:会在某种情况下自动出发执行
    
    # 2、为何要用内置方法
    # 为了定制化我们的类or对象
    
    # 3、如何用内置方法
    # __str__:在打印对象时会自动触发,然后将返回值(必须是字符串类型)当作本次打印的结果输出
    # class People:
    #     def __init__(self,name,age):
    #         self.name = name
    #         self.age = age
    #
    #     def __str__(self):
    #         return '%s %s'%(self.name,self.age)
    # obj = People('ycc',18)
    # print(obj)  # ycc 18
    
    # __del__:在清理对象时触发,会先执行该方法
    class People:
        def __init__(self,name,age):
            self.name = name
            self.age = age
            # self.x = 占据的是操作系统资源
            # self.x = open('a.txt','w')
    
        def __del__(self):
            print('run...')
            # self.x.close()
            # 发起系统调用,告诉操作系统回收相关的系统资源
    # 一:
    # obj = People('ycc',18)
    # print('====>')
    # 运行结果
    '''
    ====>
    run...
    '''
    # 程序在执行结束后,释放空间,清理垃圾,
    # 因此,这里时先运行print('====>'),然后程序结束,释放空间,清理对象,触发__del__,打印run...
    
    # 二
    obj = People('ycc',18)
    del obj
    print('====>')
    # 运行结果
    '''
    run...
    ====>
    '''
    # 这是在程序运行结束前就做了del obj的操作,因此先触发了run... 然后执行了print('====>')
    
    
    # 二次加工标准类型,描述符等晚点再学习  https://www.cnblogs.com/linhaifeng/articles/6204014.html
    
    # 判断'abc'是不是字符串
    print(isinstance('abc',str))
    
    class Foo:
        pass
    # 判断Foo是不是object的子类
    print(issubclass(Foo,object))
    
  • 反射

    # python是一门开源的强类型的动态的语言
    
    # x = 18
    # 一直到这个程序开始执行的时候,才发现其数据类型,则称为动态
    # 在程序运行前就规定好其数据类型,则称为静态
    
    # 什么是反射
    # 指的是在程序运行过程中可以'动态'获取对象的信息(数据属性+功能属性)
    
    # 为何要用反射
    
    # # 如何实现反射
    # class People:
    #     def __init__(self,name,age):
    #         self.name = name
    #         self.age = age
    #
    #     def say(self):
    #         print('%s:%s'%(self.name,self.age))
    #
    # obj = People('ycc',18)
    # print(obj.__dict__)
    #
    # # 实现反射机制的步骤
    # # 1.先通过dir:查看出某一个对象下可以.出来那些属性
    # print(dir(obj))
    #
    # # 2.可以通过字符串反射到真正的属性上,得到属性值
    # print(obj.__dict__[dir(obj)[-2]])  # ycc
    #
    # # 四个内置函数的使用
    # # 1、hasattr()  # 判断对象是否存在
    # print(hasattr(obj,'name'))  # True
    # print(hasattr(obj,'x'))  # False
    #
    # # 2、getattr()  # 获取对象属性
    # print(getattr(obj,'name'))  # ycc  相当于在做obj.name
    # print(obj.name)  # ycc
    #
    # # 3、setattr()  # 赋值对象属性
    # setattr(obj,'name','YCC')
    # print(obj.name)  # YCC
    #
    # # 4、delattr()  # 删除对象属性
    # delattr(obj,'name')
    # print(obj.__dict__)  # {'age': 18}
    #
    #
    # res1 = getattr(obj,'say')
    # # <bound method People.say of <__main__.People object at 0x000001B7AC4EDFD0>>
    # res2 = getattr(People,'say')
    # # <function People.say at 0x000001B7AC3CB550>
    # print(res1)
    # print(res2)
    
    
    
    # obj = 10
    # if hasattr(obj,'x'):
    #     print(getattr(obj,'x'))
    # else:
    #     print('属性值不存在')
    #
    # print(getattr(obj,'x',None))  # 有的话获取'x'的属性值,没有的话返回默认值None
    
    class Ftp:
        def put(self):
            print('正在上传功能')
    
        def get(self):
            print('正在下载功能')
    
        def interactive(self):
            method = input('==>: ').strip()
    
            if hasattr(self,method):
                getattr(self,method)()
            else:
                print("没有此功能")
    obj = Ftp()
    obj.interactive()
    
posted @ 2021-07-22 15:27  ccFTD  阅读(35)  评论(0)    收藏  举报