zoukankan      html  css  js  c++  java
  • Python

    什么是反射

    反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)

    Python 面向对象中的反射

    • 通过字符串的形式操作对象的属性
    • Python 中一切皆为对象,所以只要是对象都可以使用反射
    • 比如:实例对象、类对象、本模块、其他模块,因为他们都能通过 对象.属性 的方式获取、调用

    反射中关键的四个函数

    • hasattr
    • getattr
    • setattr
    • delattr

    hasattr

    def hasattr(*args, **kwargs): 
        """
        Return whether the object has an attribute with the given name.
        This is done by calling getattr(obj, name) and catching AttributeError.
    
        """
        pass
    • 返回对象是否具有具有给定名称的属性
    • 这是通过调用  getattr(obj,name) 并捕获AttributeError来完成的    

    getattr

    def getattr(object, name, default=None): 
        """
        getattr(object, name[, default]) -> value
        Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
        When a default argument is given, it is returned when the attribute doesn't
        exist; without it, an exception is raised in that case.
    
        """
        pass
    • 获取对象指定名称的属性
    •  getattr(x , y) 等价写法 x.y 
    • 当属性不存在,则返回 default 值,如果没有指定 default 就会抛出异常

    setattr

    def setattr(x, y, v):
        """
        Sets the named attribute on the given object to the specified value.
        setattr(x, 'y', v) is equivalent to ``x.y = v''
        """
        pass
    • 给指定对象的指定属性设置为值
    •  setattr(x,y,v) 等价写法 x.y = v 

    delattr

    def delattr(x, y): 
        """
        Deletes the named attribute from the given object.
        delattr(x, 'y') is equivalent to ``del x.y''
        """
        pass
    • 从指定对象中删除指定属性
    •  delattr(x,y) 等价写法 del x.y 

    反射类的成员

    class PoloBlog:
        sum = 0
    
        def __init__(self, name):
            self.name = name
    
        def test(self):
            print("====姓名==== ", self.name)

    hasattr

    blog = PoloBlog("小菠萝")
    # hasattr print(hasattr(blog, "name")) # 实例对象-实例属性 print(hasattr(blog, "sum")) # 实例对象-类属性 print(hasattr(PoloBlog, "sum")) # 类对象-类属性 print(hasattr(PoloBlog, "name")) # 类对象-实例属性 # 输出结果 True True True False

    getattr

    # getattr
    print(getattr(blog, "name"))  # 实例对象-实例属性
    print(getattr(blog, "sum"))  # 实例对象-类属性
    print(getattr(PoloBlog, "sum"))  # 类对象-类属性
    print(getattr(PoloBlog, "name", "默认值"))  # 类对象-实例属性
    
    
    # 输出结果
    小菠萝
    0
    0
    默认值

    setattr

    # 设置一个新的实例属性
    setattr(blog, "age", 24)
    
    # 设置一个新的实例方法
    setattr(blog, "printNameAge", lambda self: f"姓名:{self.name} 年龄:{self.age}")
    
    print(blog.__dict__)
    print(blog.printNameAge(blog))
    
    
    # 输出结果
    {'name': '小菠萝', 'age': 24, 'printNameAge': <function <lambda> at 0x10391a1f0>}
    姓名:小菠萝 年龄:24

    delattr

    # delattr
    delattr(blog, "age")
    delattr(blog, "printNameAge")
    print(blog.__dict__)
    
    
    # 输出结果
    {'name': '小菠萝'}

    反射本模块的成员

    除了可以检测类中有没有某个属性、方法,还可以用来检测某个模块下有没有方法、类、变量

    sums = 0
    
    
    def test1():
        print("test")
    
    
    class A():
        pass
    
    
    
    this_module = sys.modules[__name__]
    print(__name__)
    print(this_module)
    
    print(hasattr(this_module, "sums"))  # 变量
    print(hasattr(this_module, "test1"))  # 方法
    print(hasattr(this_module, "A"))  #
    
    
    # 输出结果
    __main__
    <module '__main__' from '/Users/polo/Documents/pylearn/第四章:面向对象/22_反射.py'>
    
    True
    True
    True

      

    反射其他模块的成员

    输出结果

    True
    反射22222
    小菠萝 

    fanshe 是另一个模块

    反射的应用一

    需求

    • 打开浏览器,访问一个网站
    • 单击登录就跳转到登录界面
    • 单击注册就跳转到注册界面
    • 单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理

    未使用反射前

    class Web:
        def login(self):
            print('欢迎来到登录页面')
    
        def register(self):
            print('欢迎来到注册页面')
    
        def save(self):
            print('欢迎来到存储页面')
    
    
    while True:
        obj = Web()
        choose = input(">>>").strip()
        if choose == 'login':
            obj.login()
        elif choose == 'register':
            obj.register()
        elif choose == 'save':
            obj.save()

    使用反射后

    class Web:
        def login(self):
            print('欢迎来到登录页面')
    
        def register(self):
            print('欢迎来到注册页面')
    
        def save(self):
            print('欢迎来到存储页面')
    
    
    while True:
        obj = Web()
        choose = input(">>>").strip()
        # 判断对象是否有对应的方法
        if hasattr(obj, choose):
            # 获取对应的方法
            f = getattr(obj, choose)
            # 执行方法
            f()

    反射的应用二

    在做接口自动化测试的时候,我们一般都会封装 BaseRequest 类来进行复用,类里面会封装不同请求方法

    未使用反射前

    class BaseRequest:
        req = requests.Session()
    
        def get(self, url):
            resp = self.req.get(url)
            print("==get==")
            return resp
    
        def post(self, url):
            resp = self.req.post(url)
            print("==post==")
            return resp
    
        def put(self, url):
            resp = self.req.put(url)
            print("==put==")
            return resp
    
        # 不使用反射的方法
        def main(self, method, url):
            if method == "get":
                self.get(url)
            elif method == "post":
                self.post(url)
            elif method == "put":
                self.put(url)

    使用反射后

        # 使用反射的方法
        def main_attr(self, method, url):
            if hasattr(self, method):
                func = getattr(self, method)
                func(url)

    执行代码

    request = BaseRequest()
    # 不使用反射
    request.main("get", "http://www.baidu.com")
    request.main("post", "http://www.baidu.com")
    request.main("put", "http://www.baidu.com")
    
    # 使用反射
    request.main_attr("get", "http://www.baidu.com")
    request.main_attr("post", "http://www.baidu.com")
    request.main_attr("put", "http://www.baidu.com")
    
    
    # 输出结果
    ==get==
    ==post==
    ==put==
    
    ==get==
    ==post==
    ==put==

    总结

    当封装了多个方法,然后需要根据不同条件去调用不同方法的时候,就可以考虑使用反射了,代码量少不是丁点半点

  • 相关阅读:
    flask 基础
    新的项目部署
    linux (01) linux基础
    linux (04) linux安装mysql
    linux (06) redis安装
    linux (09) nginx反向代理,负载均衡
    linux (08) nginx入门详解
    linux (07) redis详解
    linux(05) 编译安装py3
    spring-boot war包部署(二)
  • 原文地址:https://www.cnblogs.com/poloyy/p/15259431.html
Copyright © 2011-2022 走看看