zoukankan      html  css  js  c++  java
  • Python 反射

    反射说简单点 --> 就是利用字符串的形式去对象(模块)中操作(寻找/检查/删除/设置)成员。

    1.根据字符串的形式导入模块。
    2.根据字符串的形式去对象(某个模块)中操作其成员 

    说反射之前先介绍一下__import__方法,这个和import导入模块的另一种方式

    1. import  commons
    2. __import__('commons') 

    如果是多层导入:

    1. from list.text import commons 
    2. __import__(' list.text.commons',fromlist=True) #如果不加上fromlist=True,只会导入list目录

    反射即想到4个内置函数分别为:getattr、hasattr、setattr、delattr  获取成员、检查成员、设置成员、删除成员下面逐一介绍先看例子:

    class Foo():
        def __init__(self):
            self.name = 'abc'
    
        def func(self):
            return "OK"
    
    
    obj = Foo()
    # 获取成员
    ret = getattr(obj, 'func')  # 获取的是个对象
    r = ret()
    print(r)
    
    # 检查成员
    ret = hasattr(obj, 'func')  # 因为有func方法所以返回True
    print(ret)
    
    # 设置成员
    print(obj.name)  # 设置之前为:abc
    ret = setattr(obj, 'name', 19)
    print(obj.name)  # 设置之后为:19
    
    
    # 删除成员
    print(obj.name)  # abc
    delattr(obj, 'name')
    #print(obj.name)  # 报错
    OK
    True
    abc
    19

     web实例

      考虑有这么一个场景,根据用户输入的url的不同,调用不同的函数,实现不同的操作,也就是一个url路由器的功能,这在web框架里是核心部件之一。下面有一个精简版的示例:

      首先,有一个test模块,它里面有几个函数,分别用于展示不同的页面,代码如下:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Author  : Jack.Ming
    
    def login():
        print("这是一个登陆界面")
    
    def logout():
        print("这是一个退出界面")
    
    def look():
        print("这是一个浏览界面")

    其次,有一个web模块,作为程序入口,接受用户输入,展示相应的页面,代码如下:(这段代码是比较初级的写法)

    import test
    
    def run():
        inp = input("请输入您想访问页面的url: ").strip()
        if inp == "login":
            test.login()
        elif inp == "logout":
            test.logout()
        elif inp == "home":
            test.look()
        else:
            print("404")
    
    if __name__ == '__main__':
        run()

    运行该程序:

    请输入您想访问页面的url:  login
    这是一个登陆界面

    这就实现了一个简单的WEB路由功能,根据不同的url,执行不同的函数,获得不同的页面。

    如果在text模块有成千上万了函数,那么在web模块中也需要有成千上万个判断语句,那这样岂不是很麻烦,我们可以用反射的方式解决这种问题:

    反射机制(动态导入)

    仔细观察web中的代码,我们会发现用户输入的url字符串和相应调用的函数名好像!如果能用这个字符串直接调用函数就好了!但是,前面我们已经说了字符串是不能用来调用函数的。为了解决这个问题,我们可以使用getattr和hasattr这两个内置函数,代码如下:

    # !/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Author  : Jack.Ming
    def run():
        url = input("请输入URL地址:").strip()
        modules, index = url.split("/")
        obj = __import__(modules, fromlist=True)
        if hasattr(obj, index):
            func = getattr(obj, index)
            func()
        else:
            print("404 页面不存在")
    
    if __name__ == '__main__':
        run()

    运行:

    请输入URL地址:test/login
    这是一个登陆界面

    分析一下以上代码:

      首先,我们并没有定义任何一行import语句;

      其次,用户的输入URL被要求为类似“commons/home”这种格式,其实也就是模拟web框架里的url地址,斜杠左边指向模块名,右边指向模块中的成员名。

      然后,modules,index = url.split("/")处理了用户输入,使我们获得的2个字符串,并分别保存在modules和index变量里。

      接下来,最关键的是obj = __import__(modules)这一行,它让程序去导入了modules这个变量保存的字符串同名的模块,并将它赋值给obj变量。

      使用hasattr方法判断在该模块中是否有该方法。

      最后的调用中,getattr去modules模块中调用index成员的含义和以前是一样的。

      总结:通过__import__函数,我们实现了基于字符串的动态的模块导入。

     利用反射查看面向对象成员归属

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 2017/12/26 0026 15:18
    # @Author  : ming
    
    # 以字符串的形式去对象中查找成员
    class Foo:
        def __init__(self, name):
            self.Name = name
    
        def show(self):
            print("show")
    
    
    # 反射:类,只能查找类中的成员
    r = hasattr(Foo, "Name")
    print(r)
    r = hasattr(Foo, "show")
    print(r)
    
    # 反射:对象,即可查找对象,也可以查找类的成员
    obj = Foo("yang")
    r = hasattr(obj, "Name")
    print(r)
    r = hasattr(obj, "show")
    print(r)

    运行结果:

    False
    True
    True
    True

     利用反射导入模块、查找类、创建对象、查找对象中的字段

    内容如下:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 2018/1/2 0002 14:34
    # @Author  : ming
    
    # 导入模块
    m = __import__("s1", fromlist=True)
    
    # 去模块中找类
    lei = getattr(m, "Foo")
    
    # 获取类对象
    obj1 = lei("yang")
    
    # 去类中找属性值Name
    obj2 = getattr(obj1,"Name")
    
    # print
    print(obj2)
    yang
  • 相关阅读:
    has already been called for this response
    Mysql Innodb的两种表空间方式
    针对MyISAM表锁的解决方案
    MySQL数据库表修复--MyISAM
    如何修复损坏的MySQL数据表[转]
    MySQL大量unauthenticated user
    Linux基本命令篇 进程管理
    Linux 知识点滴
    Linux基本命令篇 用户管理
    Linux基本命令篇 文件管理
  • 原文地址:https://www.cnblogs.com/ming5218/p/8137130.html
Copyright © 2011-2022 走看看