目录
一、面向对象之反射
0.反射的含义
反射:自省的一种方式,利用字符串操作对象的数据和方法
用户所传递的信息都是字符串类型,所以利用反射可以与用户进行交互
1. hasattr:判断一个方法是否存在与这个类中
2. getattr:根据字符串去获取obj对象里的对应的方法的内存地址,加"()"括号即可执行
3. setattr:通过setattr将外部的一个函数绑定到实例中
4. delattr:删除一个实例或者类中的方法
1.hasattr(object,name)
判断对象是否含有某个字符串对应的属性名或者方法名
2.getattr()
根据字符串获取对象对应的属性名(值)或方法名
如果没有名字则会报错,所以常常和hasattr搭配使用
(1)案例中体会反射在与用户交互中的便捷与突破性
class C1:
name = 'duoduo'
def choice_name(self):
print('你是谁')
# 产生C1的对象
obj = C1()
1)判断某个名字是否可以被使用(存在)
# 当我们想判断对象obj中是否存在某个名字,却不想让其报错的时候可以考虑到用异常处理
try:
obj.aaa
except AttributeError:
print('不存在这个名字')
2)判断用户随意指定的名字对象是否可以使用(存在)
# 在异常处理的基础上,增加与用户交互的功能
target_name = input('请输入名字:').strip()
try:
obj.target_name
except AttributeError:
print('不存在这个名字')
3)反射的功能则可以用字符串来操作对象的数据和方法
# 反射:利用字符串操作对象的数据和方法
print(hasattr(obj, 'name')) # True
print(getattr(obj, 'name')) # duoduo
print(getattr(obj, 'choice_name')) # <bound method C1.choice_name of <__main__.C1 object at 0x103191f10>>
4)综合起来利用反射来和用户进行交互
# 利用反射的方法,来动态获取想判断的名字
class C1:
name = 'duoduo'
def choice_name(self):
print('你是谁')
obj = C1()
while True:
target_name = input('请输入名字:').strip()
if hasattr(obj,target_name):
print('有名字')
# 获取该名字对应的数据(值 函数地址)
data_or_func = getattr(obj,target_name)
if callable(data_or_func):
print('这名字是某个方法')
else:
print('这名字对应的是值')
print(data_or_func)
else:
print('没有该名字')v
3.setattr(object, name, value)
根据字符串给对象设置或者修改数据
obj1 = C1()
setattr(obj1, 'age', 18)
print(obj1.__dict__) # {'age': 18}
4.delattr(object, name)
根据字符串删除对象里面的名字
class C1:
name = 'duoduo'
def choice_name(self):
print('你是谁')
obj1 = C1() # 类C1产生了一个对象obj1
1.hasattr()判断名字是否存在
res = hasattr(obj1, 'choice_name')
print(res) # True
2.setattr() 为obj1添加属性或者方法
setattr(obj1, 'age', 18) # 为obj1增加一个属性为 age = 18
print(obj1.__dict__) # {'age': 18} 查看后在obj1中成功增加来 age = 18的属性
setattr(obj1, 'age', lambda a: a + 1)
print(obj1.__dict__) # {'age': <function <lambda> at 0x10242a280>}
3.delattr() 删除属性或者方法
delattr(obj1, 'age')
print(obj1.__dict__) # {} 空集合代表,该对象没有自己独有的功能或者属性
二、反射实战案例
1.使用反射的场景:
只要需求中出现了关键字:对象...字符串...
2.案例
(1)模拟终端
class WinCmd:
def tasklist(self):
print("""
1.学习编程
2.学习python
3.学习英语
""")
def ipconfig(self):
print("""
地址:127.0.0.1
地址:上海浦东新区
""")
def get(self, target_file):
print('获取文件', target_file)
def put(self, target_file):
print('上传文件', target_file)
def server_run(self):
print("欢迎进入简易版本cmd终端".center(50, '='))
while True:
target_cmd = input('请输入您的指令>>>:')
res = target_cmd.split(' ') # 因为在终端中输入命令常常有空格
if len(res) == 1:
if hasattr(self, res[0]):
getattr(self, res[0])() # 存在该命令则执行
else:
print(f'{res[0]}不是内部或者外部命令') # 如果传入了参数,则执行该命令并传入参数
elif len(res) == 2:
if hasattr(self, res[0]):
getattr(self, res[0])(res[1])
else:
print(f'{res[0]}不是内部或者外部命令')
obj = WinCmd() # 产生类WinCmd的对象
obj.server_run() # 调用obj的方法server_run
(2)一切皆对象
利用反射保留某个py文件中所有的大写变量名以及对应到数据值
- settings.py文件中
NAME = 'duoduo'
AGE = 13
desc = '吃饭天'
info = '没到点'
def name():
print('name')
class Person:
name = 'duoduo'
执行文件中
查看文件中的名字也可以用dir()
方法,列举对象可以使用的名字
查看文件中的名字也可以用
__dict__
方法,print(settings.__dict__)
但是文件中的名字会有很多,所以如果class类更适合用
__dict__
方法
(1)传统方法
import settings
print(dir(settings)) # dir是列举对象可以使用的名字
# ['AGE', 'NAME', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'desc', 'info']
1.方式一:for循环 + 判断
# 构造一个空字典,用来存放我们想要的名字
useful_dict = {}
for name in dir(settings):
if name.isupper(): # 保留大写
useful_dict[name] = getattr(settings,name)
print(useful_dict) # {'AGE': 13, 'NAME': 'duoduo'}
2.方式二:生成式
useful_dict = {name: getattr(settings, name) for name in dir(settings) if name.isupper()}
print(useful_dict)
# {'AGE': 13, 'NAME': 'duoduo'}
(2)利于反射动态获取
# 用反射判断settings.py文件中是否有某个名字
while True:
target_name = input('请输入您想判断的某个名字:').strip()
if hasattr(settings, target_name):
print(getattr(settings, target_name))
"""
如果存在该名字则返回值,
是方法则返回方法的内存地址<function name at 0x1004a7d30>,
如果是类名则返回类的名字<class 'settings.Person'>
"""
else:
print('该模块文件中没有该名字')
标签:obj1,__,obj,name,反射,面向对象,print,target
From: https://www.cnblogs.com/DuoDuosg/p/16867146.html