#!/usr/bin/env python # coding:utf-8 # 反射 # 对象的自省 # python中四种方法 hasattr getattr setattr delattr 都可用于类和对象, 因为python中一切皆对象, 类也是对象。
# python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射) class black_intro: feture = ‘Ugly‘ def __init__(self, name, addr): self.name = name self.addr = addr def sell_house(self): print(‘%s 正在卖房子,SB才买呢。‘ % self.name) def rent_house(self): print(‘%s 正在租房子,SB才租。‘ % self.name) b1 = black_intro(‘众家地产‘, ‘苏州‘) print(hasattr(b1, ‘name‘)) print(hasattr(b1, ‘rent_house‘)) print(hasattr(b1, ‘sale_house‘)) # False print(getattr(b1, ‘name‘)) r = getattr(b1, ‘rent_house‘) r() print(getattr(b1, ‘age‘, ‘没找到它.‘)) setattr(b1, ‘group‘, ‘二货‘) setattr(b1, ‘age‘, ‘11‘) print(b1.__dict__) setattr(b1, ‘agea‘, lambda x: x + 3) setattr(b1, ‘func‘, lambda self: self.name + ‘SB公司‘) print(b1.func(b1)) print(b1.agea(12)) delattr(b1, ‘name‘) delattr(b1, ‘age‘) print(b1.__dict__) ### 反射的应用场景 可插拨设计 # 可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用 from ftp_client import FtpClient f1 = FtpClient(‘1.1.1.1‘) # f1.put()
### hasattr 和 getattr 通常是配合使用,如果有xx方法,才去执行xx方法。 if hasattr(f1, ‘put‘): func_get = getattr(f1, ‘put‘) func_get() else: print(‘其他的逻辑‘) import sys obj = sys.modules[__name__] # 当前模块 即自己所在模块 print(‘--------->‘,hasattr(obj,‘black_intro‘)) # 判断当前模块是否有属性
上面代码中用到的一个示例模块:
class FtpClient:
‘ftp客户端,但是还么有实现具体的功能‘
def __init__(self,addr):
print(‘正在连接服务器[%s]‘ %addr)
self.addr=addr
# def put(self):
# print(‘正在上传文件‘)
类中使用的带有双下划线的 几个: __getattr__ __delattr__ __setattr__
#!/usr/bin/env python
# coding:utf-8
# 类中内置的 __getattr__ __delattr__ __setattr__
# 只有 __getattr__ 最常用
class Foo:
x = 1
def __init__(self,y):
self.y = y
def __getattr__(self, item): # 调用不存在的属性的时候会被执行
print("---------------------")
def __delattr__(self, item): # 删除的时候会调用
print("执行了删除操作__delattr__")
self.__dict__.pop(item)
# def __setattr__(self, key, value):
# print("执行了__setattr__")
# # self.key=value # 这样会无限递归, 溢出
# self.__dict__[key] = value # 直接操作字典,才是正确方式
f1 = Foo(9) # 当设置了__setattr__ 时,实例化的同时会自动执行它
print(f1.x)
f1.xxx # 触发 __getattr__
del f1.y # 删除时触发 __delattr__
f1.y1 = 33 # 设置时触发 __setattr__
print(f1.__dict__)
#!/usr/bin/env python
# coding:utf-8
class Foo:
x = 1
def __init__(self,name):
self.name = name
# def __getattr__(self, item): # 调用不存在的属性的时候会被执行
# print("---------------------")
#
# def __delattr__(self, item): # 删除的时候会调用
# print("执行了删除操作__delattr__")
# self.__dict__.pop(item)
def __setattr__(self, k, v):
print(‘设置操作 __setattr__ ‘)
# self.key=value # 这样会无限递归, 溢出
# self.__dict__[k] = v # 直接操作字典 是正确方式
if type(v) is str:
print(‘可以设置‘)
self.__dict__[k] = v.lower() # 且可以加上可控制的方法
else:
print(‘值 必须是字符串‘)
f2 = Foo(‘Alex‘)
f2.age =18
f2.gender =‘Male‘
print(f2.__dict__)
#!/usr/bin/env python
# coding:utf-8
class Foo:
x = 1
def __init__(self,name):
self.name = name
# def __getattr__(self, item): # 调用不存在的属性的时候会被执行
# print("---------------------")
def __delattr__(self, item): # 删除的时候会调用
# print("执行了删除操作__delattr__")
# self.__dict__.pop(item)
print(‘不允许删除%s‘% item) # 可以控制不允许删除
def __setattr__(self, k, v):
print(‘设置操作 __setattr__ ‘)
# self.key=value # 这样会无限递归, 溢出
# self.__dict__[k] = v # 直接操作字典
if type(v) is str:
print(‘可以设置‘)
self.__dict__[k] = v.lower() # 且可以加上可控制的方法
else:
print(‘值 必须是字符串‘)
f2 = Foo(‘Alex‘)
f2.age =18
f2.gender =‘Male‘
print(f2.__dict__)
del f2.name
print(f2.__dict__)
#!/usr/bin/env python
# coding:utf-8
# 包装,来自于继承和派生的概念,根源是基于继承的标准类型。用来定制自己的方法
class List(list):
def show_middle(self):
mid_index = int(len(self)/2)
return self[mid_index]
# 自定义的append
def append(self, obj):
if type(obj) is str:
super().append(obj)
else:
print("只能添加字符串")
l2 = list("azkaban")
print(l2,type(l2))
l3 = List(l2)
print(l3.show_middle())
l3.append(‘232‘)
print(l3)
#!/usr/bin/env python
# coding:utf-8
# 二次加工标准类型(包装)
class Foo:
x = 1
def __init__(self,y):
self.y = y
def __getattr__(self, item): # 调用不存在的属性的时候会被执行
print("[%s]属性不存在" % item)
def __getattribute__(self, item): # 不管是否找到属性都会执行。
print("执行了getattribute")
raise AttributeError(‘抛出异常了。‘) # 而在使用抛出异常之后,才会去执行 __getattr__
f2 = Foo(9)
print(f2.y)
# print(f2.age)
授权
#!/usr/bin/env python
# coding:utf-8
import time
## 类似于组合的方法
class FH:
def __init__(self,na,mo,ec="utf-8"):
self.file = open(na,mo,encoding=ec)
self.mode = mo
self.encoding = ec
def write(self,line):
t = time.strftime(‘%Y-%m-%d %X ‘)
self.file.write(‘%s %s‘%(t,line))
def __getattr__(self, item):
return getattr(self.file,item)
f1 = FH(‘a.txt‘, ‘r+‘)
f1.write(‘aaaaaaaaaaaaaaa\n‘)
f1.write(‘CPU温度过高\n‘)
f1.write(‘内存不足\n‘)
f1.write(‘硬盘剩余空间警告\n‘)
f1.seek(0) # 其实执行的是打开的文件对象的seek方法
print(f1.read())
判断实例是否属于类:
#!/usr/bin/env python
# coding:utf-8
class Foo:
pass
class bar(Foo):
pass
f1 = Foo()
print(isinstance(f1,Foo)) # 实例是否属于类
print(issubclass(bar,Foo)) # 参数1 是否 参数2 的子类
b1 = bar()
print(isinstance(b1,Foo)) # 也是True
print(type(b1)) # 查看实例的类是谁
动态导入模块:
#!/usr/bin/env python
# coding:utf-8
# 动态导入的方法:
# mt = __import__(‘m1.t‘) # 只能导入最顶级模块 点后面的不会被导入
# print(mt)
# m1.t.test1()
#
# from m1.t import test1,_test2
#
# test1()
# _test2()
import importlib
m = importlib.import_module(‘m1.t‘) # 动态导入就是基于反射的
print(m)
m.test1()
m.test2()
‘‘‘
动态导入模块方法1: __import__
说明:
1. 函数功能用于动态的导入模块,主要用于反射或者延迟加载模块。
2. __import__(module)相当于import module
举例说明:
首先创建一个模块目录lib,然后在目录内创建一个模块为:aa.py
模块代码为:
class c(object):
def __str__(self):
return ‘C language‘
在lib目录平级新建一个测试的模块,使用 __import__ 动态以字符串形式导入lib下的aa模块。
lib = __import__(‘lib.aa‘) # 相当于import lib
c = lib.aa.c()
print(c)
动态导入模块方法2:import importlib
实例还是上面的lib.aa模块,这里使用importlib进行动态导入(这个方法好理解,也是官方建议使用的)
import importlib
aa = importlib.import_module(‘lib.aa‘)
c = aa.c()
print(c)
‘‘‘
原文:https://www.cnblogs.com/FHBIAO/p/10174516.html