• 面向对象之反射和其他内置方法


    一、反射

      1、概念:主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。简而言之,就是自身调用自身即可实现已定义的某一功能,以达到简化程序的作用。

      2、python面向对象中的反射是指通过字符串的形式操作对象相关的属性。因为python中一切事物都是对象,所以都可以使用反射。一句话,就是通过字符串映射到对象的属性。

      3、示例:

    !/usr/bin/env python3
    #-*- coding:utf-8 -*-
    # write by congcong
    
    # 反射:通过字符串映射到对象的属性
    class People:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def study(self): # 绑定对象方法
            print('%s is  studying now'%self.name)
    p1 = People('cc',21)
    print(p1.name) # cc
    
    # hasattr(obj,str) 判断字符串所对应的属性是否在指定对象中存在
    print(hasattr(p1,'name')) # True 
    print(hasattr(p1,'study')) # True

    print(hasattr(People,'study')) # True
    print(hasattr(People,'name')) # False

    # getattr(obj,str,None)
    获取对象中字符串对应的属性,没有时返回None
    print(getattr(p1,'name',None)) # cc 
    print(getattr(p1,'study',None)) # <bound method People.study of <__main__.People object at 0x0000024C49773320>>
    print(getattr(People,'name',None)) # None
    print(getattr(People,'study',None)) # <function People.study at 0x000001AEE4128B70>

    # setattr(obj,str)
    # 设置属性,添加或修改属性
    setattr(p1,'sex','male') 
    setattr(p1,'age',22)
    setattr(People,
    'country','China')
    print(p1.__dict__) # {'name': 'cc', 'age': 22, 'sex': 'male'}

    print(People.__dict__)

    # {'__module__': '__main__', '__init__': <function People.__init__ at 0x00000164440C8AE8>, 'study': <function People.study at 0x00000164440C8B70>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, 'country': 'China'} # delattr(obj,str) 删除属性
    delattr(p1,'sex') 
    delattr(People,'country'
    )
    print(p1.__dict__) # {'name': 'cc', 'age': 22}
    print(People.__dict__)


    # {'__module__': '__main__', '__init__': <function People.__init__ at 0x0000021A437E8AE8>, 'study': <function People.study at 0x0000021A437E8B70>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}

      4、反射的好处

        优点1:实现可插拔机制

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

        优点2:动态导入模块(基于反射当前模块成员)

          python提供了一个特殊的方法__import__(字符串参数)通过它,我们就可以实现类似的反射功能。__import__()方法会根据参数,动态的导入同名的模块。

    import commons
    
    def run():
      inp = input("请输入您想访问页面的url: ").strip()
      modules, func = inp.split("/")
      obj = __import__("lib." + modules, fromlist=True) # 注意fromlist参数
      if hasattr(obj, func):
        func = getattr(obj, func)
        func()
      else:
        print("404")
      
    if __name__ == '__main__':
      run()
    请输入您想访问页面的url: commons/home
    这是网站主页面!
    请输入您想访问页面的url: account/find
    这是一个查找功能页面!

      5、反射的一个小例子 

    # 反射的应用
    class Handle:
        def run(self):
            exit_flag = False
            while not exit_flag:
                user_in = input('>>:').strip()
                hand_cmd = user_in.split()
                if hasattr(self,hand_cmd[0]):
                    func = getattr(self,hand_cmd[0])
                    func(hand_cmd)
                elif user_in=='q':
                    exit_flag=True
                else:
                    print('error input')
        def put(self,hand_cmd):
            print('putting now',hand_cmd)
        def get(self,hand_cmd):
            print('getting now',hand_cmd)
    f = Handle()
    f.run()
    View Code

    二、其它内置方法

      1、isinstance(object,cls) 和 issubclass(sub,super)

        <1> isinstance(object,cls) 检查是否是类cls的对象   

    class Func(object):
        pass
    obj = Func()
    print(isinstance(obj, Func)) # True

        <2> issubclass(sub, super)检查sub类是否是 super 类的子类

    class Foo(object):
        pass
    class Bar(Foo):
        pass
    print(issubclass(Bar, Foo)) # True

      2、item系列

    class Func():
        def __init__(self,name):
            self.name = name
        def __getitem__(self, item): 
            print('from getitem')
            return self.__dict__.get(item)
    def __setitem__(self, key, value): print('from setitem')
         self.__dict__[key] = value
    def __delitem__(self, key): print('from delitem')
        
    # print('del obj[key]时,执行') del self.__dict__[key]
         self.__dict__.pop(item)
    p1
    = Func('cc') print(p1.__dict__) # {'name': 'cc'} # 查看属性 print(p1['name']) # from getitem cc 触发__getitem__ print(p1.name) # cc # 设置属性 # p1.sex = 'male' # 不会触发__setitem__ p1['sex'] = 'male' # from setitem 会
    触发__setitem__
    p1['name'] = 'SC'
    p1['age'] = 21
    print(p1.__dict__) # {'name': 'SC', 'sex': 'male'
    , 'age': 21}

    # 删除属性
    #
    del p1.sex # 不会触发__delitem__
    del p1.age
    del p1['sex'] # 触发__delitem__,输出:
    from delitem
    print(p1.__dict__) # {'name': 'SC'}

      注意:<1> item系列方法, 查看p1['name'] 、设置p1['name']、del p1['name'] 才会分别触发 __getitem__、__setitem__和__delitem__内置方法,执行对应方法。

         <2>能写成p1['name']的分为两种情况:

            1、字典

            2、def  __setitem__(self, key, value):pass 

     3、attr系列

    # __setattr__,__delattr__,__getattr__
    class Fun:
        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 = Fun(66) print(f1.__dict__) # --->from setattr {'y': 66} 因为重写了__setattr__,凡是赋值操作都会触发它的执行 f1.z = 666 print(f1.__dict__) # --->from setattr {'y': 66, 'z': 666} # __getattr__只有在使用点调用属性且属性不存在时才会触发 print(f1.y) # 66 print(f1.xx) # ---> from getattr:你寻找的属性不存在 # __delattr__删除属性的时候会触发 f1.__dict__['aa'] = 6688

    print(f1.__dict__) #{'y': 66, 'z': 666, 'aa': 6688}
    del f1.aa # 触发__delattr__,输出: --->from delattr 
    print(f1.__dict__) # {'y': 66, 'z': 666}
    del f1.__dict__['y'] #未触发__delattr__
    print(f1.__dict__) # {'z': 666}
     

      注意:对于 attr 系列内置方法,只有在使用点调用属性且属性不存在时才会触发__getattr__方法;

    使用点方法添加/修改属性会触发__setattr__方法的执行;使用点方法删除属性会触发__delattr__方法。

     4、__str__类定制

    class Str:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __str__(self):
            return '<name:%s  age: %s>'%(self.name,self.age)  # 必须有返回值
    msg = Str('hello',999)
    print(msg) # <name:hello  age: 999>  打印对象时触发__str__方法,实现定制化输出

      5、__init__和__del__ 

    # 回收操作系统的资源
    class Open:
        def __init__(self,filename):
            print('open file now')
            self.filename = filename
        def __del__(self):    # 相当于self.close()等关闭操作,在此方法中进行Python不能自动回收的资源回收操作
            print('回收系统资源')
    f = Open('settings.py')   # 包含两部分操作,一是Python解释器开辟一块内存并赋给f,二是在系统硬盘层面打开了一个文件
    print('End...')  # 触发del f --> f.__del__(Python程序结束会自动回收程序中的变量,对象,但不能关闭系统资源)
    '''
    open file now
    End...
    回收系统资源
    '''
  • 相关阅读:
    python 基础 7.1 datetime 获得时间
    Python 学习笔记12
    Python 学习笔记11
    Python 学习笔记10
    Python 学习笔记9
    Python 学习笔记8
    Python 学习笔记7
    Python 学习笔记6
    Python 学习笔记5
    Python 学习笔记4
  • 原文地址:https://www.cnblogs.com/schut/p/8648157.html
Copyright © 2020-2023  润新知