这里是清安,再前面的selenium中,有用到反射来写代码,那么什么是反射,可能有些朋友还不太清楚。本章就具体实例带你学习一下反射。反射,指的是运行时获取类型定义信息。一个对象能够在运行时,像照镜子一样,反射出其类型信息。简单说,在Python中,能够通过一个对象,找出其type、class、attribute或method的能力,称为反射。反射也可以称之为魔术方法,例如:getattr()、setattr()、delattr()、hasattr()。但是魔术方法不止这些,别搞混了。
getattr
getattr():通过name返回object的属性值,当属性不存在,将使用default返回,如果没有default,则抛出AttributeError,name必须是字符串。这是getattr的源文件介绍:
def getattr(object, name, default=None): # known special case of getattr """ 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
看以下代码帮助你更快的理解,这是A.py文件的内容:
def number(num): print(f"{num}") return "我反射过来了"
这是B.py的内容
import test01 i = getattr(test01, 'number')('清安') print(i) # 清安 # 我反射过来了
这里的test01就是我的A.py,我导入了B.py文件中。前面说了name必须是字符串,所以这里的number其实是A.py文件中的函数方法,这里等价于:test01.number('qingan')。那么就有小伙伴问了,源文件里面不是有个default=None,如果没有查找到,用该值替代
o = getattr(test01, 'numbe') print(o) i = getattr(test01, 'numbe','不存在') print(i)
看这两个例子,一个用了默认值,一个没用默认值,没用默认值的且函数方法错了,那么运行之后就会告诉你这样的一个错误:
AttributeError: module 'test01' has no attribute 'numbe'
那么用了默认值的,则会告诉你"不存在"。这样的一个字样在学习的过程中,你会看到不一样的教程,getattr反射的是某类的属性,也只能是属性,要是反射其他的就会报错。但其实不然,都可以进行反射,因为函数方法也可以是属性,就比如上述例子中。那么问题来了,为什么要学这个。我们不是自动化测试吗?
if brower_type == 0 or brower_type == BrowserDriver.Chrome: driver = webdriver.Chrome() elif brower_type == 1 or brower_type == BrowserDriver.Firefox: driver = webdriver.Firefox() elif brower_type == 2 or brower_type == BrowserDriver.Ie: driver = webdriver.Ie() elif brower_type == 3 or brower_type == BrowserDriver.Edge: driver = webdriver.Edge()
上述代码中,你是否也有这么写过呢,用很多的if-elif-else来判断一个浏览器,或者定位方法。这样写难道自己觉得不多于吗,重复写了很多代码。那么如何优化呢?答案就是getattr反射。看代码:
# -->>>清安<<<--- from selenium import webdriver def driver_(option_): che = getattr(webdriver, option_)() return che class Browser: def __init__(self,option_): self.driver = driver_(option_) def open(self,url): self.driver.get(url)
这是主代码的方法,写的比较简单,但是一个实实在在的例子。我可以根据传入不同的值来打开不同的浏览器,且只有两行代码。再比较上述的写了一行又一行的代码,麻烦且重复。getattr(webdriver, option_)()等价于webdriver.option_()。这里的option_就是需要传入的驱动。那么如何传值到基类中并且调用主代码中类的函数方法呢。看代码:
from test01 import Browser driver = Browser('Chrome') driver.open('https://baidu.com')
这里就很方便了,我在Browser中传入火狐的,IE的那么就会在对应的浏览器中打开对应的百度链接。好了,对于getattr的运用介绍到这,你可以在元素定位的方法删同样运用起来,因为selenium中八大元素定位,如果你还像if-elif-else一样写,那就太磨人了。
hasattr
以下是源文件介绍:
def hasattr(*args, **kwargs): # real signature unknown """ 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吗,还加这个。当然可以直接用getattr,这里相当于增加了一个保险装置。
import requests 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 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): f = getattr(self, method) f(url) request = BaseRequest() request.main_attr("get", "https://www.baidu.com") request.main_attr("post", "https://www.baidu.com")
以上是简单的代码示例。其实这样写也是会显得代码非常的多,这里给个提示,自行想想,直接把函数方法中的get请求,post请求直接写入到反射中。这样又能节省一部分的代码了。例如:
response = getattr(requests, method)(url, json=data, headers=headers, **kwargs)
仅供参考!
后续将介绍具体的思想以及用法!