zoukankan      html  css  js  c++  java
  • Python之面向对象反射

    Python之面向对象反射

       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 类的派生类

    class Foo(object):
        pass
     
    class Bar(Foo):
        pass
     
    issubclass(Bar, Foo)

      反射:

    1 什么是反射

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

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

    四个可以实现自省的函数

    下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

    hasattr(object,name)
    判断object中有没有一个name字符串对应的方法或属性
    1 def getattr(object, name, default=None): # known special case of getattr
    2     """
    3     getattr(object, name[, default]) -> value
    4 
    5     Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    6     When a default argument is given, it is returned when the attribute doesn't
    7     exist; without it, an exception is raised in that case.
    8     """
    9     pass
    getattr(object, name, default=None)
    1 def setattr(x, y, v): # real signature unknown; restored from __doc__
    2     """
    3     Sets the named attribute on the given object to the specified value.
    4 
    5     setattr(x, 'y', v) is equivalent to ``x.y = v''
    6     """
    7     pass
    setattr(x, y, v)
    1 def delattr(x, y): # real signature unknown; restored from __doc__
    2     """
    3     Deletes the named attribute from the given object.
    4 
    5     delattr(x, 'y') is equivalent to ``del x.y''
    6     """
    7     pass
    delattr(x, y)
     1 class BlackMedium:
     2     feature='Ugly'
     3     def __init__(self,name,addr):
     4         self.name=name
     5         self.addr=addr
     6 
     7     def sell_house(self):
     8         print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)
     9     def rent_house(self):
    10         print('%s 黑中介租房子啦,傻逼才租呢' %self.name)
    11 
    12 b1=BlackMedium('万成置地','回龙观天露园')
    13 
    14 #检测是否含有某属性
    15 print(hasattr(b1,'name'))
    16 print(hasattr(b1,'sell_house'))
    17 
    18 #获取属性
    19 n=getattr(b1,'name')
    20 print(n)
    21 func=getattr(b1,'rent_house')
    22 func()
    23 
    24 # getattr(b1,'aaaaaaaa') #报错
    25 print(getattr(b1,'aaaaaaaa','不存在啊'))
    26 
    27 #设置属性
    28 setattr(b1,'sb',True)
    29 setattr(b1,'show_name',lambda self:self.name+'sb')
    30 print(b1.__dict__)
    31 print(b1.show_name(b1))
    32 
    33 #删除属性
    34 delattr(b1,'addr')
    35 delattr(b1,'show_name')
    36 delattr(b1,'show_name111')#不存在,则报错
    37 
    38 print(b1.__dict__)
    四个方法的使用演示
     1 class Foo(object):
     2  
     3     staticField = "old boy"
     4  
     5     def __init__(self):
     6         self.name = 'wupeiqi'
     7  
     8     def func(self):
     9         return 'func'
    10  
    11     @staticmethod
    12     def bar():
    13         return 'bar'
    14  
    15 print getattr(Foo, 'staticField')
    16 print getattr(Foo, 'func')
    17 print getattr(Foo, 'bar')
    类也是对象
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 
     4 import sys
     5 
     6 
     7 def s1():
     8     print 's1'
     9 
    10 
    11 def s2():
    12     print 's2'
    13 
    14 
    15 this_module = sys.modules[__name__]
    16 
    17 hasattr(this_module, 's1')
    18 getattr(this_module, 's2')
    反射当前模块成员

    导入其他模块,利用反射查找该模块是否存在某个方法

    1 #!/usr/bin/env python
    2 # -*- coding:utf-8 -*-
    3 
    4 def test():
    5     print('from the test')
    module_test.py
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3  
     4 """
     5 程序目录:
     6     module_test.py
     7     index.py
     8  
     9 当前文件:
    10     index.py
    11 """
    12 
    13 import module_test as obj
    14 
    15 #obj.test()
    16 
    17 print(hasattr(obj,'test'))
    18 
    19 getattr(obj,'test')()
     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 p=People('egon')
     8 #
     9 # People.country
    10 # print(People.__dict__)
    11 
    12 # print(p.name)
    13 # print(p.__dict__)
    14 
    15 # p.name
    16 
    17 
    18 #hasattr
    19 # print('name' in p.__dict__)
    20 # print(hasattr(p,'name'))
    21 # print(hasattr(p,'name1213'))
    22 
    23 # print(hasattr(p,'country')) #p.country
    24 # print(hasattr(People,'country')) #People.country
    25 # print(hasattr(People,'__init__')) #People.__init__
    26 
    27 
    28 #getattr
    29 # res=getattr(p,'country') #res=p.country
    30 # print(res)
    31 #
    32 # f=getattr(p,'walk') #t=p.walk
    33 # print(f)
    34 #
    35 # f1=getattr(People,'walk')
    36 # print(f1)
    37 #
    38 # f()
    39 # f1(p)
    40 
    41 
    42 # print(p.xxxxxxx)
    43 # print(getattr(p,'xxxxxxxx','这个属性确实不存在'))
    44 
    45 #
    46 # if hasattr(p,'walk'):
    47 #     func=getattr(p,'walk')
    48 #     func()
    49 #
    50 # print('================>')
    51 # print('================>')
    52 
    53 
    54 #setattr
    55 
    56 # p.sex='male'
    57 # print(p.sex)
    58 # print(p.__dict__)
    59 
    60 # setattr(p,'age',18)
    61 # print(p.__dict__)
    62 # print(p.age)
    63 # print(getattr(p,'age'))
    64 
    65 
    66 
    67 
    68 #delattr
    69 # print(p.__dict__)
    70 # del p.name
    71 # print(p.__dict__)
    72 
    73 print(p.__dict__)
    74 delattr(p,'name')
    75 print(p.__dict__)
    View Code

    3 为什么用反射之反射的好处

    好处一:实现可插拔机制

    有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

    总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

    1 class FtpClient:
    2     'ftp客户端,但是还么有实现具体的功能'
    3     def __init__(self,addr):
    4         print('正在连接服务器[%s]' %addr)
    5         self.addr=addr
    还没有实现全部功能
    1 #from module import FtpClient
    2 f1=FtpClient('192.168.1.1')
    3 if hasattr(f1,'get'):
    4     func_get=getattr(f1,'get')
    5     func_get()
    6 else:
    7     print('---->不存在此方法')
    8     print('处理其他的逻辑')
    不影响lili的代码编写

    好处二:动态导入模块(基于反射当前模块成员)

      

      反射的用途:

        

    import sys
    def add():
        print('add')
    
    def change():
        print('change')
    
    def search():
        print('search')
    
    def delete():
        print('delete')
    
    this_module=sys.modules[__name__]
    while True:
        cmd=input('>>:').strip()
        if not cmd:continue
        if hasattr(this_module,cmd):
            func=getattr(this_module,cmd)
            func()
        # if cmd in func_dic: #hasattr()
        #     func=func_dic.get(cmd) #func=getattr()
        #     func()
    
    
    # func_dic={
    #     'add':add,
    #     'change':change,
    #     'search':search,
    #     'delete':delete
    # }
    
    # while True:
    #     cmd=input('>>:').strip()
    #     if not cmd:continue
    #     if cmd in func_dic: #hasattr()
    #         func=func_dic.get(cmd) #func=getattr()
    #         func()
    
    
    # class Foo:
    #     x=1
    #     def __init__(self,name):
    #         self.name=name
    
    
    #     def walk(self):
    #         print('walking......')
    # f=Foo('egon')
    
    
    # Foo.__dict__={'x':1,'walk':....}
    # 'x' in Foo.__dict__ #hasattr(Foo,'x')
    # Foo.__dict__['x'] #getattr(Foo,'x')
    # print(Foo.x) #'x' in Foo.__dict__

      反射实现可插拔机制:

        FTP Server:

     1 import ftpclient
     2 #
     3 # print(ftpclient)
     4 # print(ftpclient.FtpClient)
     5 # obj=ftpclient.FtpClient('192.168.1.3')
     6 #
     7 # print(obj)
     8 # obj.test()
     9 
    10  
    11 
    12 #
    13 f1=ftpclient.FtpClient('192.168.1.1')
    14 if hasattr(f1,'get'):
    15     func=getattr(f1,'get')
    16     func()
    17 else:
    18     print('其他逻辑')
    View Code

        FTP Client:

     1 class FtpClient:
     2     'ftp客户端,但是还么有实现具体的功能'
     3     def __init__(self,addr):
     4         print('正在连接服务器[%s]' %addr)
     5         self.addr=addr
     6     def test(self):
     7         print('test')
     8 
     9     def get(self):
    10         print('get------->')
    View Code

      通过字符串导入模块:

    # m=input("请输入你要导入的模块:")
    
    # m1=__import__(m)  #官方不推荐
    # print(m1)      #官方不推荐
    # print(m1.time())  #官方不推荐
    
    #官方推荐使用方法
    import importlib
    t=importlib.import_module('time')
    print(t.time())

      attr系列:

      __getattr__、__setattr__、__delattr__

      setattr:为对象设置属性的时候回触发setattr的运行。

     getattr:只有在使用点调用属性且属性不存在的时候才会触发
     1 class Foo:
     2     x=1
     3     def __init__(self,y):
     4         self.y=y
     5 
     6     def __getattr__(self, item):
     7         print('----> from getattr:你找的属性不存在')
     8 
     9 
    10     def __setattr__(self, key, value):
    11         print('----> from setattr')
    12         # self.key=value #这就无限递归了,你好好想想
    13         # self.__dict__[key]=value #应该使用它
    14 
    15     def __delattr__(self, item):
    16         print('----> from delattr')
    17         # del self.item #无限递归了
    18         self.__dict__.pop(item)
    19 
    20 #__setattr__添加/修改属性会触发它的执行
    21 f1=Foo(10)
    22 print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    23 f1.z=3
    24 print(f1.__dict__)
    25 
    26 #__delattr__删除属性的时候会触发
    27 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    28 del f1.a
    29 print(f1.__dict__)
    30 
    31 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    32 f1.xxxxxx
    三者的用法演示

      定制自己的数据类型:    

    # l=list([1,2,3])
    #
    # l.append(4)
    # l.append('5')
    # print(l)
    
    # class List(list):
    #     pass
    #
    # l1=List([1,2,3])
    # print(l1)
    # l1.append(4)
    # print(l1)
    # l1.append('5')
    # print(l1)
    
    #基于继承的原理,来定制自己的数据类型(继承标准类型)
    
    # class List(list):
    #     def append(self, p_object):
    #         # print('--->',p_object)
    #         if not isinstance(p_object,int):
    #             raise TypeError('must be int')
    #         # self.append(p_object)
    #         super().append(p_object)
    #     def insert(self, index, p_object):
    #         if not isinstance(p_object,int):
    #             raise TypeError('must be int')
    #         # self.append(p_object)
    #         super().insert(index,p_object)
    #
    # l=List([1,2,3])
    # # print(l)
    # # l.append(4)
    # # print(l)
    #
    # # l.append('5')
    # print(l)
    # # l.insert(0,-1)
    # l.insert(0,'-1123123213')
    # print(l)
    
    
    # def test(x:int,y:int)->int:
    #     return x+y
    # print(test.__annotations__)
    #
    # print(test(1,2))
    # print(test(1,'3'))
    #
    # def test(x,y):
    #     return x+y
    
    
    #不能用继承,来实现open函数的功能
    # f=open('a.txt','w')
    # print(f)
    # f.write('1111111')
    
    #授权的方式实现定制自己的数据类型
    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('111111
    ')
    # f.write('111111
    ')
    # f.write('111111
    ')
    
    
    f=Open('b.txt','r+')
    # print(f.write)
    print(f.read)
    
    res=f.read() #self.x.read()
    print(res)
    
    print('=-=====>',f.read())
    f.seek(0)
    print(f.read())
    # f.flush()
    # f.close() 

      作业:

     1 #基于继承来定制自己的数据类型
     2 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
     3     def append(self, p_object):
     4         ' 派生自己的append:加上类型检查'
     5         if not isinstance(p_object,int):
     6             raise TypeError('must be int')
     7         super().append(p_object)
     8     #
     9     @property
    10     def mid(self):
    11         '新增自己的属性'
    12         index=len(self)//2
    13         return self[index]
    14 
    15 
    16 # l=List([1,2,3])
    17 
    18 # print(l.mid)
    19 
    20 #基于授权来定制自己的数据类型:
    21 
    22 # class Open:
    23 #     def __init__(self,filepath,mode,encode='utf-8'):
    24 #         self.f=open(filepath,mode=mode,encoding=encode)
    25 #         self.filepath=filepath
    26 #         self.mode=mode
    27 #         self.encoding=encode
    28 
    29 #     def write(self,line):
    30 #         print('write')
    31 #         self.f.write(line)
    32 
    33 #     def __getattr__(self, item):
    34 #         return getattr(self.f,item)
    35 
    36 # # f=Open('a.txt','w')
    37 # # f.write('123123123123123
    ')
    38 # # print(f.seek)
    39 # # f.close()
    40 # #
    41 # # f.write('111111
    ')
    42 
    43 
    44 # f=open('b.txt','w')
    45 # f.write('bbbbbb
    ')
    46 # f.close()
    47 # print(f)
    48 
    49 
    50 
    51 # class Foo:
    52 #     def test(self):
    53 #         pass
    54 #
    55 # print(getattr(Foo,'test'))
    56 #
    57 # obj=Foo()
    58 # print(getattr(obj,'test'))
    59 
    60 
    61 
    62 class List:
    63     def __init__(self,x):
    64         self.seq=list(x)
    65 
    66     def append(self,value):
    67         if not isinstance(value,str):
    68             raise TypeError('must be str')
    69         self.seq.append(value)
    70     @property
    71     def mid(self):
    72         index=len(self.seq)//2
    73         return self.seq[index]
    74     def __getattr__(self, item):
    75         return getattr(self.seq,item)
    76 
    77     def __str__(self):
    78         return str(self.seq)
    79 
    80 l=List([1,2,3])
    81 
    82 l.append('1')
    83 
    84 print(l.mid)
    85 l.insert(0,123123123123123123123123123)
    86 # print(l.seq)
    87 
    88 print(l)
    89 
    90 
    91 obj.name='egon'
    92 del obj.name
    View Code

    链接:详细

  • 相关阅读:
    Leetcode 12. Integer to Roman
    Leetcode 133. Clone Graph
    Leetcode 199. Binary Tree Right Side View
    Leetcode 200. Number of Islands
    React通过Ajax获取数据
    canvas鼠标点击划线
    制作图片墙
    CSS制作翻牌特效
    输入框制作方法
    初来咋到
  • 原文地址:https://www.cnblogs.com/george92/p/9233865.html
Copyright © 2011-2022 走看看