第六种方式,python使用cached_property缓存装饰器和自定义cached_class_property装饰器,动态添加类属性(三),selnium webdriver类无限实例化控制成单浏览器。
使用 from lazy_object_proxy.utils import cached_property,使用这个装饰器。
由于官方的行数比较少,所以可以直接复制出来用自己的。
class cached_property(object): # 这是官方的
def __init__(self, func):
self.func = func def __get__(self, obj, cls):
print (obj,cls)
if obj is None: return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value class cached_class_property(object): # 这是修改的
def __init__(self, func):
self.func = func def __get__(self, obj, cls):
print (obj,cls)
if obj is None: return self
value = cls.__dict__[self.func.__name__] = self.func(obj)
return value class A():
@cached_property # 使用这个实例属性的缓存装饰器,然后替换为property装饰器和自定义的cached_class_property测试
def result(self):
print ('compute result')
return 1+2 a1 = A()
a1.result # 第一次
a1.result # 第二次
a2 = A()
a2.result # 第三次
1、如果使用cached_property这个装饰器,是把result方法的结果绑定到实例的字典中,所以一共打印了两次 'compute result' ,分别是第一次 第三次打印的,第二次因为a1这个实例的字典中有result这个属性了,所以不执行这个方法了。
2、 如果使用property装饰器,毫无疑问就是会打印三次 'compute result'
3、下面来个更激进一点的装饰器,cached_property这个实例属性装饰器虽然能缓存结果,但是新的实例还是会调用这个方法进行1+2计算。做一点小改变,把obj.__dict__换成cls.__dict__,也就是改成cached_class_property,这样就是类属性缓存器,这样就只会打印一次'compute result'了,perfect了,利用这个对基类添加动态属性太好了,好处包括:
1)不像之前的元类和那种装饰器写法,动态添加进来的属性和方法,使用时候不能在pycharm自动补全提示,说的补全指的是打 self.r 就会补全出self.result,打self.result.就会补全出一个整形int类的所有方法了,因为1+2等于3,3是整形。
2、相比于基类在__init__或者new中添加方法,如果动态添加属性的类作为基类被继承,当子类也写了init方法时候,必须显式手动去调用父类的init方法。
4、这只是举个例子,1 + 2这么简单的东西不需要使用缓存的,如果调用result属性不频繁是没必要使用这个装饰器的,但有的对象创建是经过了很久的运行步骤的,当频繁使用这个属性,造成很多没必要的计算,或者有的结果是一个io过程得到的,更要使用这样装饰器了。用这个作为selenium的webdriver包装类的driver属性也很不错,加上他,就可以十分任性的随意实例化你写的webdriver类了,不会每实例化一次都新弹出一次浏览器。 从包的名字就可以看出缓存器也叫延迟加载,如果直接写成类属性那么还没开始使用这个属性就已经执行运算了,比如直接写成类下面作为类属性,还没准备需要使用浏览器,就早早的弹出个浏览器出来,没什么必要。
5、把上一篇的webdriver改一下,控制为单浏览器就是这样了。
# coding:utf-8 import logging
import unittest
from selenium import webdriver class DriverWrapper():
def __init__(self): self.logger = logging.getLogger(self.__class__.__name__)
self.logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(filename)s - %(lineno)d - %(levelname)s - %(message)s', "%Y-%m-%d %H:%M:%S"))
self.logger.addHandler(stream_handler)
@cached_class_property ## 添加一个类属性缓存装饰器
def driver(self):
self.driver = webdriver.Chrome() def open(self, url):
self.driver.get(url) def find_element_by_css_selector(self, css_str): # 使用自定义的方法覆盖了原方法,比如先打印出一段话
self.logger.debug('要查找的元素的css选择器是 --> ' + css_str)
self.driver.find_element_by_css_selector(css_str) def __getattr__(self, item): #想把其他的webdriver的操作方法直接添加进来,不一个一个的再写一个方法然后调用driver属性的方法,不想一直搞冗余的代码,可以这么做。python先使用__getattribute__,查不到才会调用__getsttr__方法,利用这个特性,来实现这个添加driver的属性到自己类里面
return getattr(self.driver, item) class _Test(unittest.TestCase):
def test(self):
driver_wrapper = DriverWrapper()
driver_wrapper.open('https://www.baidu.com') # 有人不喜欢用get,可以叫open什么的
driver_wrapper.find_element_by_css_selector('#kw') # 当类中存在方法,使用了自己类里面的方法,所以每次使用css选择器查找元素时候会打印一个日志
driver_wrapper.find_element_by_id('kw') # 当类中不存在此方法,使用Chrome类的方法 driver_warpper.driver.close() # 这样做也可以,但不算是动态添加属性了,这是直接使用的该实例的driver属性的方法,driver属性是Chrome的一个实例。 if __name__ == '__main__':
unittest.main()
6、此时就可以非常任性的在任何测试用例中任何函数中去实例化DriverWrapper类了,而不用依赖有webdriver实例化的测试用例方法必须先运行
7、无限实例化DriverWrapper类还想弄成单浏览器也可以借鉴享元模式或者单例模式。但抽成装饰器后,使用到其他的类中也是通用的,节约代码。不然很多代码中出现同一段相似的判断,看着稍微low点。
第六种方式,python使用cached_property缓存装饰器和自定义cached_class_property装饰器,动态添加类属性(三),selnium webdriver类无限实例化控制成单浏览器。的更多相关文章
- python类属性和类方法(类的结构、实例属性、静态方法)
类属性和类方法 目标 类的结构 类属性和实例属性 类方法和静态方法 01. 类的结构 1.1 术语 —— 实例 使用面相对象开发,第 1 步 是设计 类 使用 类名() 创建对象,创建对象 的动作有两 ...
- python 四种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,直接修改类属性的值
三种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,类名就是类对象,city就是类变量, #coding=utf-8 class empl ...
- python干货-类属性和方法,类的方法重写
类属性与方法 类的私有属性 __private_attrs: 两个下划线开头,表明为私有,外部不可用,内部使用时self.__private_attrs. 类的方法 在类的内部,使用 def 关键字来 ...
- python小知识-属性查询优先级(如果有同名类属性、数据描述符、实例属性存在的话,实例>类>数据描述符)
https://www.cnblogs.com/Jimmy1988/p/6808237.html https://segmentfault.com/a/1190000006660339 https:/ ...
- python类属性用法总结
属性的定义:python中的属性其实是普通方法的衍生. 操作类属性有三种方法: 1.使用@property装饰器操作类属性. 2.使用类或实例直接操作类属性(例如:obj.name,obj.age=1 ...
- python3 速查参考- python基础 8 -> 面向对象基础:类的创建与基础使用,类属性,property、类方法、静态方法、常用知识点概念(封装、继承等等见下一章)
基础概念 1.速查笔记: #-- 最普通的类 class C1(C2, C3): spam = 42 # 数据属性 def __init__(self, name): # 函数属性:构造函数 self ...
- Python之路-面向对象&继承和多态&类属性和实例属性&类方法和静态方法
一.面向对象 编程方式 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强…” 什么是面 ...
- 我的Python学习笔记(四):动态添加属性和方法
一.动态语言与静态语言 1.1 动态语言 在运行时代码可以根据某些条件改变自身结构 可以在运行时引进新的函数.对象.甚至代码,可以删除已有的函数等其他结构上的变化 常见的动态语言:Object-C.C ...
- 【17】有关python面向对象编程的提高【多继承、多态、类属性、动态添加与限制添加属性与方法、@property】
一.多继承 案例1:小孩继承自爸爸,妈妈.在程序入口模块再创建实例调用执行 #father模块 class Father(object): def __init__(self,money): self ...
随机推荐
- mac OS X:[11]如何添加打印机
苹果菜单中,单击下拉列表中的『系统偏好设置』: 或在Dock上,单击『系统偏好设置』图标. 2 在『系统偏好设置』窗口中,单击『打印机与扫描仪』图标. 3 在『打印机与扫描仪』窗口中,单击打印机框架下 ...
- Centos7下Yum安装PHP5.5,5.6,7.0
默认的版本太低了,手动安装有一些麻烦,想采用Yum安装的可以使用下面的方案: 1.检查当前安装的PHP包 yum list installed | grep php 如果有安装的PHP包,先删除他们 ...
- 安装redis出现cc adlist.o /bin/sh:1:cc:not found
安装redis时 提示执行make命令时, 提示 CC adlist.o /bin/sh: cc: 未找到命令 问题原因:这是由于系统没有安装gcc环境,因此在进行编译时才会出现上面提示,当安装好gc ...
- POST数据时400错误
第一种解决办法是关闭Csrf public function init(){ $this->enableCsrfValidation = false; } 第二种解决办法是在form表单中加入隐 ...
- 微信小程序——收起和查看更多功能
项目中做一些列表的时候,可能会需要做到 查看更多 及 收起功能,如下图所示: 大概的需求就是默认只显示2条,点击[查看更多]显示全部,点击[收起]还原. 实现的方法千万种.我来讲一下我的实现思路: 1 ...
- android选取系统相册图片后,识别图中二维码
项目中添加设备操作需要扫描二维码,考虑到多种扫码方式,也添加直接识别二维码图片的操作. 首先跳转系统相册选取图片 Intent intent = new Intent(Intent.ACTION_PI ...
- Python 类的多态的运用
#类的多态的运用 #汽车类 class Car(object): def move(self): print("move ...") #汽车商店类 class CarStore(o ...
- SQLITE WITH ENTITY FRAMEWORK CODE FIRST AND MIGRATION
Last month I’ve a chance to develop an app using Sqlite and Entity Framework Code First. Before I st ...
- 1、QT分析之QApplication的初始化
原文地址:http://blog.163.com/net_worm/blog/static/1277024192010097430321/ 在开始分析之前交代一下,一是分析的QT在Window平台实现 ...
- grub的boot loader安装在磁盘上的位置
在很多资料上介绍grub的引导过程时,都是:bios->MBR->boot loaderboot loader是grub或者lilo.但是他是放在什么位置?很多资料上都没有标明. 通过阅读 ...