~~面向对象进阶(三):反射~~

进击の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('输入错误。。。。')

这样就可以明确的感觉到反射的好处


*这个很有用*
*不学就吃亏*
posted @ 2019-07-24 00:00  吃夏天的西瓜  阅读(331)  评论(0编辑  收藏  举报