第五种方式,python使用组合来添加类方法和属性(二),以selenium的webdriver为例

组合优点多,但经常比继承需要额外的代码。

上一篇是 介绍装饰器、继承、元类、mixin,四种給类动态添加类属性和方法的四种方式。

此篇介绍直接把被组合的类的属性直接加入到类里面,前面的四个例子很简单,这次来个实际例子的举例。

# coding:utf-8

import logging
import unittest
from selenium import webdriver class DriverWrapper():
def __init__(self):
self.driver = webdriver.Chrome()
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) 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()

1、这样就是组合来动态添加方法和属性了,DriverWrapper类的实例可以直接使用一切Chrome类的实例的方法和属性。

2、如果不重写__getattr__方法,那么driver_wrapper.find_element_by_id('kw')  这么做就会报错,因为DriverWrapper类没有定义过这个方法。

一共五种方法动态扩展。

但元类 装饰器 和此篇的组合然后重写__getattr__来添加方法和属性,有个重大弊端是,因为太动态了,pycharm写代码时候,不能自动补全这些被扩展添加的方法和属性,这个是硬伤,因为pycahrm只能普通的代码理解,但整段的代码运行结果他理解不了。然后看代码时候苦难一点。

上一篇:poj2513--并查集+欧拉路+字典树


下一篇:ios AudioQueueStart returns -50 录音失败问题