• 反射


    一.反射

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象

    1 class Foo(object):
    2     pass
    3  
    4 obj = Foo()
    5  
    6 isinstance(obj, Foo)

    issubclass(sub, super)检查sub类是否是 super 类的派生类

     1 class Bar():
     2     pass
     3 class Foo(Bar):
     4     pass
     5 obj=Foo()
     6 print(Foo.__bases__)   #判断是不是继承类
     7 print(issubclass(Foo,Bar))
     8 
     9 
    10 
    11 
    12 (<class '__main__.Bar'>,)
    13 True

    1.什么是反射

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

     2.python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

    hasattr(object,name)

      1.文件直接运行,把一个文件当成脚本运行

      2.当成模块导入

     1 class People:
     2     country='China'
     3     def __init__(self,name):
     4         self.name=name
     5 
     6 p=People('egon')
     7 print(p.__dict__)
     8 People.country    #调的不是字符串
     9 #hasattr
    10 print('name' in p.__dict__)
    11 print(hasattr(p,'name'))
    12 print(hasattr(p,'country'))   #p.country
    13 print(hasattr(People,'country'))  #People.country
    14 print(hasattr(People,'__init__')) #People.__init__
    15 
    16 
    17 {'name': 'egon'}
    18 True
    19 True
    20 True
    21 True
    22 True

    getattr(object,name,default=None)

     1 class People:
     2     country='China'
     3     def __init__(self,name):
     4         self.name=name
     5     def walk(self):
     6         print('%s is walking' %self.name)
     7 
     8 p=People('egon')
     9 
    10 
    11 #getattr
    12 res=getattr(p,'country')  #res=p.country
    13 print(res)
    14 
    15 f=getattr(p,'walk')  #t=p.walk
    16 print(f)
    17 
    18 f1=getattr(People,'walk')  #类的函数属性
    19 print(f1)
    20 
    21 f()   #绑定方法第一个参数不用传
    22 f1(p)  #函数不会自动传值
    23 
    24 China
    25 <bound method People.walk of <__main__.People object at 0x00000000004D1978>>
    26 <function People.walk at 0x00000000004CE2F0>
    27 egon is walking
    28 egon is walking
     1 print(getattr(p,'xxxx','这个属性确实不存在'))  #保证程序不会抛出异常
     2 #或者是用下面这个
     3 
     4 if hasattr(p,'walk'):
     5     func=getattr(p,'walk')
     6     func()
     7 print('=======>')
     8 
     9 
    10 
    11 这个属性确实不存在
    12 egon is walking
    13 =======>
    14 =======>

    setattr(x,y,z)

     1 p.sex='male'
     2 print(p.sex)
     3 print(p.__dict__)
     4 setattr(p,'age',18)
     5 print(p.__dict__)
     6 print(p.age)
     7 print(getattr(p,'age'))
     8 
     9 
    10 
    11 
    12 male
    13 {'sex': 'male', 'name': 'egon'}
    14 {'sex': 'male', 'name': 'egon', 'age': 18}
    15 18
    16 18

    delattr(x,y)

     1 # print(p.__dict__)
     2 # del p.name
     3 # print(p.__dict__)
     4 print(p.__dict__)
     5 delattr(p,'name')
     6 print(p.__dict__)
     7 
     8 
     9 
    10 
    11 {'name': 'egon'}
    12 {}

    3.反射当前模块的属性  

    this_module=sys.modules[__name__]

    import sys
    
    x=11
    class Foo:
        pass
    def s1():
        print('s1')
    
    def s2():
        print('s2')
    
    this_module = sys.modules[__name__]    #获取当前模块
    print(this_module)
    
    print(hasattr(this_module,'s1'))
    print(getattr(this_module,'s2'))
    print(this_module.s2)
    print(this_module.s1)
    
    
    <module '__main__' from 路径
    True
    <function s2 at 0x00000000006BE2F0>
    <function s2 at 0x00000000006BE2F0>
    <function s1 at 0x00000000006BE268>

    4.反射的用途:

    1.把字符串映射成可执行过程

    2.实现可插拔机制

    1 while True:
    2     cmd=input('>>:').strip()
    3     if not cmd:continue
    4     # if cmd in func_dic:
    5     #     func=func_dic.get(cmd) #hasattr
    6     #     func()                 #func=getattr()
    7     if hasattr(this_module,cmd):
    8         func=getattr(this_module,cmd)
    9         func()
    1 class FtpClient:
    2     'ftp客户端,但是还没有实现具体的功能'
    3     def __init__(self,addr):
    4         print('正在连接服务器[%s]' %addr)
    5         self.addr=addr
     1 import ftpclient
     2 #from module import FtpClient
     3 f1=ftpclient.FtpClient('192.168.1.1')
     4 if hasattr(f1,'get'):   #有木有get方法
     5     func_get=getattr(f1,'get')
     6     func_get()
     7 else:
     8     print('---->不存在此方法')
     9     print('处理其他的逻辑')
    10 # print(ftpclient)
    11 # print(ftpclient.FtpClient)
    12 
    13 
    14 
    15 
    16 正在连接服务器[192.168.1.1]
    17 ---->不存在此方法
    18 处理其他的逻辑

    通过字符串导入模块

     1 m=input('请输入你要导入的模块:')
     2 m1=__import__(m)
     3 print(m1)
     4 print(m1.time())
     5 
     6 #推荐使用方法
     7 import importlib
     8 t=importlib.import_module('time')
     9 print(t.time())
    10 
    11 
    12 
    13 请输入你要导入的模块:time
    14 <module 'time' (built-in)>
    15 1493021033.3454628

    手动加上类型限制,弥补python没有类型限制的不足。

     1 class Foo:
     2     def __init__(self,name):
     3         self.name=name
     4 
     5     def __setattr__(self,key,value):  #都是把属性加到字典里的,递归超过最大限制
     6         if not isinstance(value,str):
     7             raise TypeError('must be str')
     8         # print('---setattr---key:%s,value:%s' %(key,value))
     9         #setattr(self,key,value)  #self.key=value 递归了,一直再设置属性 #都是把属性加到字典里的,递归超过最大限制
    10         self.__dict__[key]=value  #使用它
    11 
    12     def __delattr__(self, item):
    13         print('---> from delattr')
    14         self.__dict__.pop(item)
    15 
    16 f1=Foo('egon')
    17 f1.age='18'
    18 print(f1.name)
    19 print(f1.age)
    20 print(f1.__dict__)  ## 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    21 
    22 f1.__dict__['a']=3
    23 del f1.age
      print(f1.__dict__) ##字典里还有age

     1 class Foo:
     2     def __init__(self,x):
     3         self.name=x
     4     #属性不存在的情况下才会触发
     5     def __getattr__(self, item):
     6         print('getattr-->%s %s' %(item,type(item)))
     7 
     8 f=Foo('egon')
     9 print(f.xxx)
    10 
    11 
    12 
    13 getattr-->xxx <class 'str'>
    14 None     #返回None

    5.二次加工标准类型

    定制自己的数据类型

    定制列表里只加数字

     1 class List(list):    ##继承内置的数据类型
     2     def append(self, p_object):
     3         if not isinstance(p_object,int):
     4             raise TypeError('must be int')
          #self.append(p_object) 作为对比,这个不对的
    5 super().append(p_object) #完成真正的append 6 l=List([1,2,3]) 7 print(l) 8 l.append(4) 9 print(l) 10 11 l.insert(0,-1) 12 l.insert(0,'123') 13 print(l) 14 15 16 [1, 2, 3] 17 [1, 2, 3, 4] 18 ['123', -1, 1, 2, 3, 4]

    规范提示数据类型:

     1 def test(x:int,y:int)->int:
     2     return x+y
     3 print(test.__annotations__)
     4 
     5 print(test(1,2))
     6 # print(test(1,'3'))
     7 
     8 
     9 
    10 
    11 {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
    12 3

    1.使用继承的原理二次加工

     1 class List(list):
     2     def append(self, p_object):
     3         if not isinstance(p_object,int):
     4             raise TypeError('must be int')
     5         #self.append(p_object)
     6         super().append(p_object)
     7     # def insert(self, index, p_object):
     8     #     if not isinstance(p_object,int):
     9     #         raise TypeError('must be int')
    10     #     #self.append(p_object)
    11     #     super().insert(index,p_object)
    12 l=List([1,2,3])
    13 print(l)
    14 l.append(4)
    15 # print(l)
    16 print(l)
    17 l.insert(0,-1)
    18 print(l)
    19 # l.insert(0,'123')
    20 # print(l)
    21 
    22 
    23 [1, 2, 3]
    24 [1, 2, 3, 4]
    25 [-1, 1, 2, 3, 4]

     2.授权的方式实现定制自己的数据类型

    授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

    实现授权的关键点就是覆盖__getattr__方法

     1 #不能用继承,来实现open函数的功能
     2 # f=open('a.txt','w')
     3 # print(f)
     4 # f.write('111')
     5 import time
     6 class Open:
     7     def __init__(self,filepath,m='r',encode='utf-8'):
     8         self.x=open(filepath,mode=m,encoding=encode)
     9         self.filepath=filepath
    10         self.mode=m
    11         self.encoding=encode
    12     def write(self,line):
    13         print('f自己的write',line)
    14         t=time.strftime('%Y-%m-%d %X')
    15         self.x.write('%s %s'%(t,line))
    16 
    17 f=Open('b.txt','w')
    18 print(f)
    19 f.write('1111
    ')
    20 f.write('11111
    ')
    21 f.write('11111
    ')
    22 f.write('11111
    ')
    import time
    class Open:
        def __init__(self,filepath,m='r',encode='utf-8'):
            self.x=open(filepath,mode=m,encoding=encode)
            self.filepath=filepath
            self.mode=m
            self.encoding=encode
        def write(self,line):
            print('f自己的write',line)
            t=time.strftime('%Y-%m-%d %X')
            self.x.write('%s %s'%(t,line))
    
        def __getattr__(self, item):
            print('=------>',item,type(item))
            return (getattr(self.x,item))
    
    # f=Open('b.txt','w')
    # print(f)
    # f.write('1111
    ')
    # f.write('11111
    ')
    # f.write('11111
    ')
    # f.write('11111
    ')
    
    f=Open('b.txt','r+')
    print(f.read)
    
    res=f.read()  #self.x.read()
    print(res)
    print('=-==>',f.read())
    f.seek(0)
    print(f.read())
    # f.flush()
    # f.close()
    
    
    =------> read <class 'str'>
    <built-in method read of _io.TextIOWrapper object at 0x00000000008EEA68>
    =------> read <class 'str'>
    2017-04-24 17:49:50 1111
    2017-04-24 17:49:50 11111
    2017-04-24 17:49:50 11111
    2017-04-24 17:49:50 11111
    
    =------> read <class 'str'>
    =-==> 
    =------> seek <class 'str'>
    =------> read <class 'str'>
    2017-04-24 17:49:50 1111
    2017-04-24 17:49:50 11111
    2017-04-24 17:49:50 11111
    2017-04-24 17:49:50 11111

    模拟open()打开文件

    import time
    class Open():
        def __init__(self,filepath):
            self.path=filepath
            self.x=open(filepath,'w+')
        def write(self,value):
            t=time.strftime('%Y-%m-%d')
            self.x.write(t+value)
        def __getattr__(self, item):
            if hasattr(self.x,item):
                return getattr(self.x,item)
    
    f=Open('a.txt')
    f.read()
    f.seek(0)
    f.flush()
  • 相关阅读:
    tctip demo页面>
    tctip demo页面>
    tctip demo页面>
    tctip demo页面>
    tctip demo页面>
    tctip demo页面>
    关于值类型与列类型不匹配,所需类型是 DataRow"的解决方案
    如何给excel设置密码
    Excel如何将大写字符转化为小写
    C#调用WebService(服务引用-xml)
  • 原文地址:https://www.cnblogs.com/jiangshitong/p/6758323.html
Copyright © 2020-2023  润新知