Python - 面向对象编程 - 反射 hasattr、getattr、getattr、delattr

时间:2021-09-13 10:50:58   收藏:0   阅读:47

什么是反射

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

 

Python 面向对象中的反射

 

反射中关键的四个函数

 

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

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

 

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

 

delattr

def delattr(x, y): 
    """
    Deletes the named attribute from the given object.
    delattr(x, ‘y‘) is equivalent to ``del x.y‘‘
    """
    pass

 

反射类的成员

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==

 

总结

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

 

原文:https://www.cnblogs.com/poloyy/p/15259431.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!