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

一、反射

  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...
回收系统资源
'''
原文地址:https://www.cnblogs.com/schut/p/8648157.html