~~面向对象进阶(三):反射~~
进击の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('输入错误。。。。')
这样就可以明确的感觉到反射的好处