进击のpython
神奇的反射
定义:通过字符串的形式操作对象相关的属性
由于python一切皆对象
所以,都可以使用反射!
什么意思呢?,我现在,写一个类
class Person(object):
def __init__(self):
self.age = None
self.name = None
pass
我现在想要知道我的类,有没有一个属性叫做name2
可以吧,这也是一个请求
那怎么做呢?
p = Person()
if p.name2:
print("我在类的属性里")
这么写吗?
不对吧,当你这么写的时候,p.name2也实际上就是在调用是吧
那我没有是不是肯定要报错啊
AttributeError: 'Person' object has no attribute 'name2'
结果也确实是如我们所分析的那样
那这种时候,就用到反射了!
那我们就要学习反射的第一个方法
hasattr
他是来查询你的类里面有没有一个属性的方法的
示例如下
if hasattr(p, "name2"): print("我在类的属性里")
其中传的参数先后是(类的实例,你要查询的属性)
看好奥,查询的属性要用字符串的形式
这是不是就是通过字符串来操作对象的相关属性
执行一下发现什么都没有
将name2⇨name
发现下面的话成功打印了
能理解吧(因为name2不在里面,返回的是False)
其实反射就像我们所学习到的数据类型一样,也是存在增删改查的
getattr()获取
hassttr()检查
setattr()赋值
deattr()删除
因为传入的是字符串形式,所以也就可以认为是通过字符串的形式
来操作对象的相关属性
getattr
a = getattr(p, "name") print(a)
获取p实例里面name属性的值
能理解吧(打印结果为None,因为上述代码属性就是None)
你看,你是不是通过字符串的模式,就获取到a了
但是有什么用呢?
这可是太有用了!
你想想熬,你这个Person里面多了一些方法,比如walk speak等等
那用户在进行操作程序的时候
键入命令是不是都是字符串形式的!
懂我意思了吧
当用户的键入信息在类里有,我们就执行,否则就不执行
user_input = input("请输入指令:") if hasattr(p, user_input): a = getattr(p, user_input) a()
请输入指令:walk 没病走两步
对吧!
当我输入指令的时候,我就键入“walk”这个指令
判断一下是不是在实例的方法里啊
在是吧!
然后获取到这个方法(函数)
最后再将函数调用
这就是简单的反射应用场景
setattr
setattr(p, "sex", "Female") print(p.sex)
赋值,给你的p实例新增加了一个叫sex的属性
同时将它赋值为Female
这样我在下面打印的时候就打印出来不会报错
(原实例里没有这个属性,如果不写setattr是会报错的)
这种属性,是静态的
那我们怎么样可以设置一个方法呢?
首先,因为我知道我的这个方法是要传进类里的
所以在类外面定义的时候
我先在括号里填上实例对象self
def talk(self): print(f"{self.sex}逼逼叨!")
然后再在外面设置setattr方法
setattr(p, "sex", "Female") setattr(p, "talk", talk)
(实例对象,方法名(自定义),函数名)
最后调用的时候,要把实例传进去!
p.talk(p)
方法名那里多说一下
并不需要和函数名起名一致
setattr(p, "shuohua", talk) p.shuohua(p)
因为他是函数的调用名,所以你怎么叫,他就怎么调用
同时还要注意,最后一个参数放的是函数名!没有()
而且啊,不要思维定势
不光可以给实例加方法
你也可以给类加方法啊
setattr(Person, "shuohua", talk) p.shuohua()
对吧!
所以你就可以看出来
其实最好的绑定方法是要给类绑定
因为要是给实力绑定,还要自己传实例
delattr
print(p.age) delattr(p, "age") print(p.age)
执行结果可以看到
None AttributeError: 'Person' object has no attribute 'age'
第一行打印属性
第二行将这个属性删除
第三行再想打印就找不到了
就报错了
但是其实你会发现一个问题
就是这个方法其实和 del 差不多
del p.age
也是可以的
那说了这么多,反射可以怎么做呢?
一个简单的例子就可以知道了
现在让我们打开购物车,访问一个菜单,你单击登录就跳转到登录界面,你单击注册就跳转到注册界面,等等
其实你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理。
没学反射之前的解决方式
class User:
def login(self):
print('欢迎来到登录页面')
def register(self):
print('欢迎来到注册页面')
def save(self):
print('欢迎来到存储页面')
while 1:
choose = input('>>>').strip()
if choose == 'login':
obj = User()
obj.login()
elif choose == 'register':
obj = User()
obj.register()
elif choose == 'save':
obj = User()
obj.save()
对吧
一点一点的写
那要是学完反射
我们就可以这么写了!
class User:
def login(self):
print('欢迎来到登录页面')
def register(self):
print('欢迎来到注册页面')
def save(self):
print('欢迎来到存储页面')
user = User()
while 1:
choose = input('>>>').strip()
if hasattr(user, choose):
func = getattr(user, choose)
func()
else:
print('输入错误。。。。')
这样就可以明确的感觉到反射的好处