• 4月17日 python学习总结 反射、object内置方法、元类


    一、反射    

    下述四个函数是专门用来操作类与对象属性的,如何操作?

    通过字符串来操作类与对象的属性,这种操作称为反射

    class People:
        country="China"
        def __init__(self,name):
            self.name=name
        def tell(self):
            print('%s is aaa' %self.name)
    
    obj=People('egon')
    
    1、hasattr 
    print(hasattr(People,'country'))
    print('country' in People.__dict__)
    
    print(hasattr(obj,'name'))
    print(hasattr(obj,'country'))
    print(hasattr(obj,'tell'))
    
    2、getattr  #只有在使用点调用属性且属性不存在的时候才会触发
    x=getattr(People,'country1',None)
    print(x)
    
    f=getattr(obj,'tell',None)#obj.tell
    print(f == obj.tell)
    f()
    obj.tell()
    
    
    3、setattr   
    People.x=111
    setattr(People,'x',111)
    print(People.x)
    
    obj.age=18
    setattr(obj,"age",18)
    print(obj.__dict__)
    
    4、delattr
    del People.country
    delattr(People,"country")
    print(People.__dict__)
    
    del obj.name
    delattr(obj,"name")
    print(obj.__dict__)

      

     

    class Foo:
        x=1
        def __init__(self,y):
            self.y=y
    
        def __getattr__(self, item):
            print('----> from getattr:你找的属性不存在')
    
    
        def __setattr__(self, key, value):
            print('----> from setattr')
            # self.key=value #这就无限递归了,你好好想想
            # self.__dict__[key]=value #应该使用它
    
        def __delattr__(self, item):
            print('----> from delattr')
            # del self.item #无限递归了
            self.__dict__.pop(item)
    
    #__setattr__添加/修改属性会触发它的执行
    f1=Foo(10)
    print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    f1.z=3
    print(f1.__dict__)
    
    #__delattr__删除属性的时候会触发
    f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f1.a
    print(f1.__dict__)
    
    #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    f1.xxxxxx
    例子

     

      应用实例

    class Foo:
        def run(self):
            while True:
                cmd=input('cmd>>: ').strip()
                # print('%s run...' %cmd)
                if hasattr(self,cmd):
                    func=getattr(self,cmd)
                    func()
    
        def download(self):
            print('download....')
    
        def upload(self):
            print('upload...')
    
    # obj=Foo()
    # obj.run()

    二、object内置方法

        __str__ 、__del__、__call__等没有设置也是默认就有的,从object类中继承来,不做任何操作,此处是在重写父类方法

      1、__str__()方法 在打印对象时触发     

    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
        def __str__(self):
            # print('========>')
            return '<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex)
    
    obj=People('egon',18,'male')
    print(obj)            #执行时相当于print(obj.__str__())
    
    # l=list([1,2,3])
    # print(l)

      2、__del__()  析构函数    对象删除时触发  

          eg:  

           1. del 对象名 删除对象 2. 程序结束释放内存空间时  3. 对象被垃圾回收机制回收时

          在对象被创建时,若有打开文件或手动开辟内存空间等操作,在删除对象,这些系统资源没有被释放,就必须要用__del__方法主动释放内存空间  

                  

    import time
    
    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
        def __del__(self): # 在对象被删除的条件下,自动执行
            print('__del__')
    
    
    obj=People('egon',18,'male')
    
    del obj #obj.__del__()
    
    time.sleep(5)

    应用      

    class MyOpen:
        def __init__(self,filepath,mode="r",encoding="utf-8"):
            self.filepath=filepath
            self.mode=mode
            self.encoding=encoding
            self.fobj=open(filepath,mode=mode,encoding=encoding)
    
        def __str__(self):
            msg="""
            filepath:%s
            mode:%s
            encoding:%s
            """ %(self.filepath,self.mode,self.encoding)
            return msg
    
        def __del__(self):
            self.fobj.close()
    
    # f=open('a.txt',mode='r',encoding='utf-8')
    
    f=MyOpen('aaa.py',mode='r',encoding='utf-8')
    # print(f.filepath,f.mode,f.encoding)
    # print(f)
    
    # print(f.fobj)
    res=f.fobj.read()
    print(res)

      3、__call__ 方法  调用对象时触发(可用于元类控制类的实例化

    class Foo:
         def __init__(self):
             pass
         def __str__(self):
             return '123123'
    
         def __del__(self):
             pass
    
         # 调用对象,则会自动触发对象下的绑定方法__call__的执行,
         # 然后将对象本身当作第一个参数传给self,将调用对象时括号内的值
         #传给*args与**kwargs
         def __call__(self, *args, **kwargs):
             print('__call__',args,kwargs)

    三、元类

      1、cexec()函数

        exec(code , global , local) 将第一个参数code中的代码解析,其中的全局变量以字典形式放到第二个参数global中,局部变量以字典形式放到第三个参数 local中

    code="""
    global x
    x=0
    y=2
    """
    global_dic={'x':100000}
    local_dic={}
    exec(code,global_dic,local_dic)
    
    print(global_dic)
    print(local_dic)
    
    
    code="""
    x=1
    y=2
    def f1(self,a,b):
        pass
    """
    local_dic={}
    exec(code,{},local_dic)
    print(local_dic)

      2、一切皆对象,类也是对象,类的类是什么呢?

         类的类就是元类     

      我们用class定义的类使用来产生我们自己的对象

      内置元类type是用来专门产生class定义的类的

     

    1、用内置的元类type,来实例化得到我们的类

    class_name='Chinese'
    class_bases=(object,)
    class_body="""
    country="China"
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    def speak(self):
        print('%s speak Chinese' %self.name)
    """
    class_dic={}
    exec(class_body,{},class_dic)
    
    类的三大要素
    print(class_name,class_bases,class_dic)
    
    Chinese=type(class_name,class_bases,class_dic)
    print(Chinese)
    
    p=Chinese('egon',18,'male')
    print(p.name,p.age,p.sex)

     2、自定义元类:

    class Mymeta(type):
        # 来控制类Foo的创建
        def __init__(self,class_name,class_bases,class_dic): #self=Foo
            # print(class_name)
            # print(class_bases)
            # print(class_dic)
            if not class_name.istitle():
                raise TypeError('类名的首字母必须大写傻叉')
    
            if not class_dic.get('__doc__'):
                raise TypeError('类中必须写好文档注释,大傻叉')
    
            super(Mymeta,self).__init__(class_name,class_bases,class_dic)
    
        # 控制类Foo的调用过程,即控制实例化Foo的过程
        def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={}
            # print(self)
            # print(args)
            # print(kwargs)
    
            #1 造一个空对象obj
            obj=object.__new__(self)
    
            #2、调用Foo.__init__,将obj连同调用Foo括号内的参数一同传给__init__
            self.__init__(obj,*args,**kwargs)
    
            return obj
    
    
    
    #Foo=Mymeta('Foo',(object,),class_dic)
    class Foo(object,metaclass=Mymeta):
        """
        文档注释
        """
        x=1
        def __init__(self,y):
            self.Y=y
    
        def f1(self):
            print('from f1')
    
    
    obj=Foo(1111) #Foo.__call__()
    
    # print(obj)
    # print(obj.y)
    # print(obj.f1)
    # print(obj.x)

    单例设计模式:就是只有一个对象的模式,就算是创建多次对象指向的也是同一个对象地址

     第一种实现方式:

    # 单例模式
    import settings
    
    class MySQL:
        __instance=None
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
        @classmethod
        def singleton(cls):
            if not cls.__instance:
                obj=cls(settings.IP, settings.PORT)        #setting中的IP 和PORT是固定值
                cls.__instance=obj
            return cls.__instance
    
    
    
    # obj4=MySQL(settings.IP,settings.PORT)
    # print(obj4.ip,obj4.port)
    
    obj4=MySQL.singleton()
    obj5=MySQL.singleton()
    obj6=MySQL.singleton()
    
    print(obj4 is obj5 is obj6)

    第二种:通过元类

      

    #方式二:定制元类实现单例模式
    # import settings
    #
    # class Mymeta(type):
    #     def __init__(self,name,bases,dic): #定义类Mysql时就触发
    #
    #         # 事先先从配置文件中取配置来造一个Mysql的实例出来
    #         self.__instance = object.__new__(self)  # 产生对象
    #         self.__init__(self.__instance, settings.HOST, settings.PORT)  # 初始化对象
    #         # 上述两步可以合成下面一步
    #         # self.__instance=super().__call__(*args,**kwargs)
    #
    #
    #         super().__init__(name,bases,dic)
    #
    #     def __call__(self, *args, **kwargs): #Mysql(...)时触发
    #         if args or kwargs: # args或kwargs内有值
    #             obj=object.__new__(self)
    #             self.__init__(obj,*args,**kwargs)
    #             return obj
    #
    #         return self.__instance
    #
    #
    #
    #
    # class Mysql(metaclass=Mymeta):
    #     def __init__(self,host,port):
    #         self.host=host
    #         self.port=port
    #
    #
    #
    # obj1=Mysql() # 没有传值则默认从配置文件中读配置来实例化,所有的实例应该指向一个内存地址
    # obj2=Mysql()
    # obj3=Mysql()
    #
    # print(obj1 is obj2 is obj3)
    #
    # obj4=Mysql('1.1.1.4',3307)

    第三种: 装饰器

    # 方式三:定义一个装饰器实现单例模式
    # import settings
    #
    # def singleton(cls): #cls=Mysql
    #     _instance=cls(settings.HOST,settings.PORT)
    #
    #     def wrapper(*args,**kwargs):
    #         if args or kwargs:
    #             obj=cls(*args,**kwargs)
    #             return obj
    #         return _instance
    #
    #     return wrapper
    #
    #
    # @singleton # Mysql=Singleton(Mysql)
    # class Mysql:
    #     def __init__(self,host,port):
    #         self.host=host
    #         self.port=port
    #
    #
    #
    # obj1=Mysql()
    # obj2=Mysql()
    # obj3=Mysql()
    # print(obj1 is obj2 is obj3) #True
    #
    # obj4=Mysql('1.1.1.3',3307)
    # obj5=Mysql('1.1.1.4',3308)
    # print(obj3 is obj4) #Fals

     

    作业:    

    '''
    4-17日作业
    '''
    '''
        1、判断一个对象是否属于str类型,判断一个类是否是另外一个类的子类
    '''
    a='123'
    print(isinstance(a,str))
    print(issubclass(str,object))
    
    '''
        2、有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类(放到了另外一个文件中),但是egon去跟女朋友度蜜月去了,还没有完成他写的类,
            class FtpClient:
                """
                ftp客户端,但是还么有实现具体的功能
                """
                def __init__(self,addr):
                    print('正在连接服务器[%s]' %addr)
                    self.addr=addr
    
                此处应该完成一个get功能
        lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
    '''
    
    class FtpClient:
        """
        ftp客户端,但是还么有实现具体的功能
        """
    
        def __init__(self, addr):
            print('正在连接服务器[%s]' % addr)
            self.addr = addr
    f=FtpClient('egon')
    addr=getattr(f,'addr')
    print(addr)
    
    
    '''
    
        3、定义一个老师类,定制打印对象的格式为‘<name:egon age:18 sex:male>’
    '''
    class Teacher:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
        def __str__(self):
            return '<name: %s  age: %s  sex: %s>'%(self.name,self.age,self.sex)
    t=Teacher('egon',18,'male')
    print(t)
    
    '''
     4、定义一个自己的open类,控制文件的读或写,在对象被删除时自动回收系统资源
    '''
    class MyOpen:
        def __init__(self,file,io,encoding):
            self.file=file
            self.io=io
            self.encoding=encoding
            self.my_open=open(self.file,self.io,encoding=self.encoding)
        def __del__(self):
            self.my_open.close()
            print('guan bi wen jian')
    
    mo=MyOpen(r'F:pythonobjectdays2days23setting.py','rt','utf-8')
    del mo
    
    '''
      5、自定义元类,把自定义类的数据属性都变成大写,必须有文档注释,类名的首字母必须大写
    '''
    class Mymeta(type):
        def __init__(self,class_name,class_base,class_dict):
            dict={}
            for name in class_dict:
                if not name.istitle():
                    new_name=name.capitalize()
                dict.update({new_name:class_dict[name]})
            print(dict)
            super().__init__(class_name,class_base,dict)
            if not class_name.istitle():
                raise TypeError('类名必须首字母大写')
            if not class_dict.get('__doc__'):
                raise TypeError('类必须有文档注释')
    class My(object,metaclass=Mymeta):
        '''
        MY 1233123
        '''
        char='123'
        def abc(self):
            print(self.char)
    m=My()
    print(My.__dict__)
    
    
    
    '''
    
        6、用三种方法实现单例模式,参考答案:http://www.cnblogs.com/linhaifeng/articles/8029564.html#_label5
    '''
    
    
    
    class Mymeta(type):
        __obj = ''
        def __call__(self, *args, **kwargs):
            if self.__obj=='':
                self.__obj=self.__new__(self)
                self.__obj.__init__(*args, **kwargs)
            return self.__obj
    class My(object,metaclass=Mymeta):
        '''
        MY 1233123
        '''
        char='123'
        def abc(self):
            print(self.char)
    m = My()
    m2 = My()
    m3 = My()
    print(m, m2, m3)

        

  • 相关阅读:
    Java学习资源整理(超级全面)
    Java中的Iterable与Iterator详解
    git使用笔记1:结合Github远程仓库管理项目
    关于LeetCode上链表题目的一些trick
    关于链表中哨兵结点问题的深入剖析
    关于Java中基类构造器的调用问题
    大整数相乘问题总结以及Java实现
    快速排序实现及其pivot的选取
    阿里云服务器部署Java Web项目全过程
    Git 学习总结
  • 原文地址:https://www.cnblogs.com/95lyj/p/8871682.html
Copyright © 2020-2023  润新知