python项目设计之 接口 抽象类抽象方法 组合 依赖注入 程序设计原则 企业应用设计
接口概念
接口有两种:
1、URL接口
2、对子类进行约束
说接口概念之前我们先说一下在其他语言中不叫继承对于基类和派生类,而叫实现。
接口是派生类实现接口类而进行约束派生类的。接口中的方法不能写功能,而派生类实现了接口就需要把接口的所有方法都实现一遍。
接口的约束性
1 # 其他语言接口类型 interface 只要继承(实现)接口类,那么派生类(子类)中必须有这个基类(父类)的方法,所以接口是用来约束的。 2 interface 接口: 3 4 def f1(self): 5 pass 6 7 class lei(接口): 8 9 def f1(self): 10 print(123)
python中没有接口类型
python中没有接口类型,单是我们可以人为的创造 约束给类。 raise 抛出异常来强制实现基类方法来做接口 用来约束,接口中不建议写其他不用来约束的方法
1 # python 接口构造 2 3 class IOrderRepository: 4 5 def fettch_one_by(self,nid): 6 """ 7 #获取单条数据 8 :param nid: 9 :return: 10 """ 11 raise Exception("子类中必须实现该方法") 12 13 class OrderRepository(IOrderRepository): 14 15 def __init__(self): 16 pass 17 def fettch_one_by(self,nid): 18 pass 19 20 obj = OrderRepository() 21 obj.fettch_one_by(1) 22 23 24 25 26 # 接口类 必须实现 切不能写任何代码,其他语言写了就报错,python我们规定不写。但不会报错 27 class IFoo: 28 def f1(self): 29 """ 30 31 :return: 32 """ 33 raise Exception("子类必须实现该方法") 34 35 class Bar(IFoo): 36 def __init__(self): 37 pass
abc模块实现抽象类
1 import abc 2 class Foo(metaclass=abc.ABCMeta): # 定义抽象类 3 # 普通方法 用来实现继承 4 def f1(self): 5 print("抽象类的普通方法") 6 7 #抽象方法 8 @abc.abstractmethod 9 def f2(self): 10 """ 11 抽象方法 子类必须实现该方法 否则报错 12 :return: 13 """ 14 15 class Bar(Foo): 16 17 def f2(self): 18 print("这是子类中的抽象方法实现,不实现否则报错") 19 20 obj = Bar() 21 obj.f2()
继承抽象类的类,如果不实现抽象类中的抽象方法,会报错,实现了约束;还可以写其他的功能
如果抽象类中没有定义抽象方法,那就相当于提供了一个类的功能;如果抽象类中定义了全部方法为抽象方法,那就相当于提供了一个接口的功能
__new__方法:
如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时 ,
Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写 __new__(),
那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。
1 在Python中存在于类里面的构造方法__init__()负责将类的实例化,而在__init__()启动之前,__new__()决定是否 要使用该__init__()方法, 2 因为__new__()可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。 3 4 如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参数则是生产所需原料,__init__()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。 5 而__new__()则是生产部经理,__new__()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。 6 7 __new__()方法的特性: 8 __new__()方法是在类准备将自身实例化时调用。 9 __new__()方法始终都是类的静态方法,即使没有被加上静态方法装饰器。是因为无论怎样重写类的__new__()函数,追溯到源头都是继承自object的__new__()函数,而object类中定义的__new__()函数就被定义成了静态函数,被@stacitmethod修饰 10 11 12 # 类的实例化和它的构造方法通常都是这个样子: 13 class MyClass(object): 14 def __init__(self, *args, **kwargs): 15 ... 16 # 实例化 17 myclass = MyClass(*args, **kwargs) 18 #正如以上所示,一个类可以有多个位置参数和多个命名参数,而在实例化开始之后,在调用 __init__()方法之前,Python首先调用__new__()方法: 19 def __new__(cls, *args, **kwargs): 20 ... 21 第一个参数cls是当前正在实例化的类。 22 如果要得到当前类的实例,应当在当前类中的__new__()方法语句中调用当前类的父类 的__new__()方法。 23 例如,如果当前类是直接继承自object,那当前类的__new__()方法返回的对象应该为: 24 def __new__(cls, *args, **kwargs): 25 ... 26 return object.__new__(cls) 27 28 #注意: 29 事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时 ,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写 __new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。 30 而如果新式类中重写了__new__()方法,那么你可以自由选择任意一个的其他的新式类(必定要是 新式类,只有新式类必定都有__new__(),因为所有新式类都是object的后代,而经典类则没有__new__() 方法)的__new__()方法来制造实例,包括这个新式类的所有前代类和后代类,只要它们不会造成递归死 循环。具体看以下代码解释: 31 32 class Foo(object): 33 def __init__(self, *args, **kwargs): 34 ... 35 def __new__(cls, *args, **kwargs): 36 return object.__new__(cls, *args, **kwargs) 37 38 # 以上return等同于 39 # return object.__new__(Foo, *args, **kwargs) 40 41 class Child(Foo): 42 def __new__(cls, *args, **kwargs): 43 return object.__new__(cls, *args, **kwargs) 44 # 如果Child中没有定义__new__()方法,那么会自动调用其父类的__new__()方法来制造实例,即Foo.__new__(cls, *args, **kwargs)。 45 46 # 在任何新式类的__new__()方法,不能调用自身的__new__()来制造实例,因为这会造成死循环。因此必须避免类似以下的写法: 47 # 在Foo中避免:return Foo.__new__(cls, *args, **kwargs)或return cls.__new__(cls, *args, **kwargs)。Child同理。 48 49 50 51 52 53 # 因此可以这么描述__new__()和__ini__()的区别,在新式类中__new__()才是真正的实例化方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__()使其丰满。 54 # 如果以建房子做比喻,__new__()方法负责开发地皮,打下地基,并将原料存放在工地。而__init__()方法负责从工地取材料建造出地皮开发招标书中规定的大楼,__init__()负责大楼的细节设计,建造,装修使其可交付给客户;
1 class A(object): 2 def __new__(cls, x): 3 print('this is in A.__new__, and x is ', x) 4 print('this is in A.__new__, and cls is ', cls) 5 return super(A, cls).__new__(cls) 6 7 def __init__(self, y): 8 print('this is in A.__init__, and y is ', y) 9 10 11 class C(object): 12 def __new__(cls, n): 13 print('this is in C.__new__, and n is ', n) 14 return super(C, cls).__new__(cls) 15 16 def __init__(self, a): 17 print('this is in C.__init__, and a is ', a) 18 19 20 class B(A): 21 def __new__(cls, z): 22 print('this is in B.__new__, and z is ', z) 23 return A.__new__(cls, z) 24 # 25 # def __init__(self, m): 26 # print('this is in B.__init__, and m is ', m) 27 28 # class B(A): 29 # def __new__(cls, z): 30 # print 'this is in B.__new__, and z is ', z 31 # return object.__new__(cls) 32 # def __init__(self, m): 33 # print 'this is ni B.__init__, and m is ', m 34 35 if __name__ == '__main__': 36 a = A(100) 37 print('=' * 20) 38 b = B(200) 39 print(type(b)) 40 41 结果: 42 this is in A.__new__, and x is 100 43 this is in A.__new__, and cls is <class '__main__.A'> 44 this is in A.__init__, and y is 100 45 ==================== 46 this is in B.__new__, and z is 200 47 this is in A.__new__, and x is 200 48 this is in A.__new__, and cls is <class '__main__.B'> 49 this is in A.__init__, and y is 200 50 <class '__main__.B'> 51 52 # 1.由注释掉的代码执行结果可以看出,B类虽然继承自A类,但是如果没有重写B类的__new__()函数,则默认继承的仍是object基类的__new__(),而不是A的; 53 # 2.B类的__new__()函数会在B类实例化时被调用,自动执行其中的代码语句,但是重写__new__()函数不会影响类的实例化结果,也就是说不管写return时返回的是A的还是object的,B类的实例化对象就是B类的,而不会成为A类的实例化对象;只是在实例化时,如果返回的是A.__new__(cls),则会执行A类中定义的__new__()函数;
小结:
1、继承自object的新式类才有__new__
2、__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别
3、__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例
4、__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
5、如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是cls来保证是当前类实例,如果是其他类的类名,那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__init__函数。
__call__方法:
1 __call__()的用法: 2 一句话总结:一个对象后面加括号会执行这个对象类的__call__方法 3 4 __call__()方法能够让类的实例对象,像函数一样被调用; 5 >>> class A(object): 6 def __call__(self, x): 7 print '__call__ called, print x: ', x 8 9 10 >>> 11 >>> a = A() 12 >>> a('123') 13 __call__ called, print x: 123 14 >>> 15 16 看a('123')这是函数的调用方法,这里a实际上是类对象A的实例对象,实例对象能像函数一样传参并被调用,就是__call__()方法的功能;
元类:
1 python中的元类Metaclass 2 3 理解元类之前需要学习的知识: 4 5 1.type 6 python的自建函数type(),作用是返回一个参数的类型,但是实际上,它也接受一个类的一些描述作为参数,然后返回一个类。 7 8 type()函数的语法是这样的: 9 10 type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值)) 11 12 13 例子: 14 class ReedSun(ShuaiGe): 15 shuai = True 16 def test(x): 17 return x+2 18 # 就等价于 19 type("ReedSun", (ShuaiGe,), {"shuai":True, "test":lambda x: x+2}) 20 # (属性和方法本质上都是方法) 21 在python中,类也是对象,当我们使用class关键词创建一个类的时候,Python解释器仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。 22 23 24 25 元类是什么?元类实际上就是用来创建类的东西。为了帮助我们理解,我们可以这样想,我们创建类就是为了创建类的实例,同样的,我们创建元类就是为了创建类。元类就是类(实例)的类,就像下面这样 26 27 Metaclass() = class 28 class() = object # object==>实例 29 30 理解了什么是元类,我们再来看一看type()函数。 31 其实type就是一个元类,type就是我们用来创建所有的类的元类。(如果我们要创建自己定义的元类的话,也要从type中继承) 32 33 34 元类的工作原理 35 我们来看一下下面这个例子 36 37 class ReedSunMetaclass(type): 38 pass 39 40 class Foo(object, metaclass = ReedSunMetaclass): 41 pass 42 43 class Bar(Foo): 44 pass 45 46 47 首先,我们创建了一个元类ReedSunMetaclass(默认习惯,元类的类名总是以Metaclass结尾,表示这是一个元类)。 48 然后,我们又用元类ReedSunMetaclass创建了一个Foo类,(同时,Foo类的属性__metaclass__就变成了ReedSunMetaclass)。 49 最后,我们创建了一个子类Bar继承自Foo。 50 51 我们来试着理解一下在python内部是怎么执行这几个步骤的: 52 对于父类Foo,Python会在类的定义中寻找__metaclass__属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类。很显然,它找到了。 53 对于子类Bar, python会先在子类中寻找__metaclass__属性,如果找到了,Python就会用它来创建类Bar,如果没有找到,就再从父类中寻找,直到type。显然,它在父类中找到了。 54 我们可以看到使用元类的一个好处了,即他可以让子类隐式的继承一些东西。 55 56 57 58 自定义元类 59 元类的主要目的就是为了当创建类时能够自动地改变类。创建类我们需要定义__new__()函数,__new__ 是在__init__之前被调用的特殊方法,是用来创建对象并返回之的方法。我们举个例子来说明定义自定义元类的方法。 60 61 __new__()方法接收到的参数依次是: 62 1. 当前准备创建的类的对象; 63 2. 类的名字; 64 3. 类继承的父类集合; 65 4. 类的方法集合。 66 67 class ReedSunMetaclass(type): 68 def __new__(cls, name, bases, attrs): 69 # 添加一个属性 70 attrs['哈哈哈'] = True 71 return type.__new__(cls, name, bases, attrs) 72 73 https://blog.csdn.net/weixin_35955795/article/details/52985170 74 http://blog.jobbole.com/21351/
1 class ProxyMetaclass(type): 2 def __new__(cls, name, bases, attrs): 3 # print(name) # 输出Crawler 4 count = 0 5 attrs['__CrawlFunc__'] = [] # 创建一个__CrawlFunc__类方法集合的列表 6 for k, v in attrs.items(): # attrs类的方法集合 7 if 'crawl_' in k: 8 attrs['__CrawlFunc__'].append(k) 9 count += 1 10 attrs['__CrawlFuncCount__'] = count 11 for k, v in attrs.items(): 12 print(k, v) 13 return type.__new__(cls, name, bases, attrs) 14 15 16 class Crawler(object, metaclass=ProxyMetaclass): 17 def get_proxies(self, callback): 18 proxies = [] 19 for proxy in eval("self.{}()".format(callback)): 20 print('成功获取到代理', proxy) 21 proxies.append(proxy) 22 return proxies 23 24 # def crawl_daxiang(self): 25 # url = 'http://vtp.daxiangdaili.com/ip/?tid=559363191592228&num=50&filter=on' 26 # html = get_page(url) 27 # if html: 28 # urls = html.split('\n') 29 # for url in urls: 30 # yield url 31 32 33 # def crawl_daili66(self, page_count=4): 34 # """ 35 # 获取代理66 36 # :param page_count: 页码 37 # :return: 代理 38 # """ 39 # start_url = 'http://www.66ip.cn/{}.html' 40 # urls = [start_url.format(page) for page in range(1, page_count + 1)] 41 # for url in urls: 42 # print('Crawling', url) 43 # html = get_page(url) 44 # if html: 45 # doc = pq(html) 46 # trs = doc('.containerbox table tr:gt(0)').items() 47 # for tr in trs: 48 # ip = tr.find('td:nth-child(1)').text() 49 # port = tr.find('td:nth-child(2)').text() 50 # yield ':'.join([ip, port]) 51 52 # def crawl_proxy360(self): 53 # """ 54 # 获取Proxy360 55 # :return: 代理 56 # """ 57 # start_url = 'http://www.proxy360.cn/Region/China' 58 # print('Crawling', start_url) 59 # html = get_page(start_url) 60 # if html: 61 # doc = pq(html) 62 # lines = doc('div[name="list_proxy_ip"]').items() 63 # for line in lines: 64 # ip = line.find('.tbBottomLine:nth-child(1)').text() 65 # port = line.find('.tbBottomLine:nth-child(2)').text() 66 # yield ':'.join([ip, port]) 67 def crawl_proxy360(self, page_count=9): 68 """ 69 获取Proxy360 70 :return: 代理 71 """ 72 start_url = 'http://www.swei360.com/?page={}' 73 urls = [start_url.format(page) for page in range(1, page_count + 1)] 74 for url in urls: 75 print('Crawling', url) 76 html = get_page(url) 77 if html: 78 doc = pq(html) 79 lines = doc('#list tbody tr').items() 80 for line in lines: 81 ip = line.find('td:nth-child(1)').text() 82 port = line.find('td:nth-child(2)').text() 83 yield ':'.join([ip, port]) 84 85 def crawl_goubanjia(self): 86 """ 87 获取Goubanjia 88 :return: 代理 89 """ 90 start_url = 'http://www.goubanjia.com/free/gngn/index.shtml' 91 html = get_page(start_url) 92 if html: 93 doc = pq(html) 94 tds = doc('td.ip').items() 95 for td in tds: 96 td.find('p').remove() 97 yield td.text().replace(' ', '') 98 99 def crawl_ip181(self): 100 start_url = 'http://www.ip181.com/' 101 html = get_page(start_url) 102 ip_address = re.compile('<tr.*?>\s*<td>(.*?)</td>\s*<td>(.*?)</td>') 103 # \s* 匹配空格,起到换行作用 104 re_ip_address = ip_address.findall(html) 105 for address, port in re_ip_address: 106 result = address + ':' + port 107 yield result.replace(' ', '') 108 109 # def crawl_ip3366(self): 110 # for page in range(1, 4): 111 # start_url = 'http://www.ip3366.net/free/?stype=1&page={}'.format(page) 112 # html = get_page(start_url) 113 # ip_address = re.compile('<tr>\s*<td>(.*?)</td>\s*<td>(.*?)</td>') 114 # # \s * 匹配空格,起到换行作用 115 # re_ip_address = ip_address.findall(html) 116 # for address, port in re_ip_address: 117 # result = address + ':' + port 118 # yield result.replace(' ', '') 119 120 def crawl_kxdaili(self): 121 for i in range(1, 11): 122 start_url = 'http://www.kxdaili.com/ipList/{}.html#ip'.format(i) 123 html = get_page(start_url) 124 ip_address = re.compile('<tr.*?>\s*<td>(.*?)</td>\s*<td>(.*?)</td>') 125 # \s* 匹配空格,起到换行作用 126 re_ip_address = ip_address.findall(html) 127 for address, port in re_ip_address: 128 result = address + ':' + port 129 yield result.replace(' ', '') 130 131 def crawl_premproxy(self): 132 for i in ['China-01', 'China-02', 'China-03', 'China-04', 'Taiwan-01']: 133 start_url = 'https://premproxy.com/proxy-by-country/{}.htm'.format(i) 134 html = get_page(start_url) 135 if html: 136 ip_address = re.compile('<td data-label="IP:port ">(.*?)</td>') 137 re_ip_address = ip_address.findall(html) 138 for address_port in re_ip_address: 139 yield address_port.replace(' ', '') 140 141 def crawl_xroxy(self): 142 for i in ['CN', 'TW']: 143 start_url = 'http://www.xroxy.com/proxylist.php?country={}'.format(i) 144 html = get_page(start_url) 145 if html: 146 ip_address1 = re.compile("title='View this Proxy details'>\s*(.*).*") 147 re_ip_address1 = ip_address1.findall(html) 148 ip_address2 = re.compile("title='Select proxies with port number .*'>(.*)</a>") 149 re_ip_address2 = ip_address2.findall(html) 150 for address, port in zip(re_ip_address1, re_ip_address2): 151 address_port = address + ':' + port 152 yield address_port.replace(' ', '') 153 154 def crawl_kuaidaili(self): 155 for i in range(1, 4): 156 start_url = 'http://www.kuaidaili.com/free/inha/{}/'.format(i) 157 html = get_page(start_url) 158 if html: 159 ip_address = re.compile('<td data-title="IP">(.*?)</td>') 160 re_ip_address = ip_address.findall(html) 161 port = re.compile('<td data-title="PORT">(.*?)</td>') 162 re_port = port.findall(html) 163 for address, port in zip(re_ip_address, re_port): 164 address_port = address + ':' + port 165 yield address_port.replace(' ', '') 166 167 def crawl_xicidaili(self): 168 for i in range(1, 3): 169 start_url = 'http://www.xicidaili.com/nn/{}'.format(i) 170 headers = { 171 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 172 'Cookie': '_free_proxy_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWRjYzc5MmM1MTBiMDMzYTUzNTZjNzA4NjBhNWRjZjliBjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMUp6S2tXT3g5a0FCT01ndzlmWWZqRVJNek1WanRuUDBCbTJUN21GMTBKd3M9BjsARg%3D%3D--2a69429cb2115c6a0cc9a86e0ebe2800c0d471b3', 173 'Host': 'www.xicidaili.com', 174 'Referer': 'http://www.xicidaili.com/nn/3', 175 'Upgrade-Insecure-Requests': '1', 176 } 177 html = get_page(start_url, options=headers) 178 if html: 179 find_trs = re.compile('<tr class.*?>(.*?)</tr>', re.S) 180 trs = find_trs.findall(html) 181 for tr in trs: 182 find_ip = re.compile('<td>(\d+\.\d+\.\d+\.\d+)</td>') 183 re_ip_address = find_ip.findall(tr) 184 find_port = re.compile('<td>(\d+)</td>') 185 re_port = find_port.findall(tr) 186 for address, port in zip(re_ip_address, re_port): 187 address_port = address + ':' + port 188 yield address_port.replace(' ', '') 189 190 def crawl_ip3366(self): 191 for i in range(1, 4): 192 start_url = 'http://www.ip3366.net/?stype=1&page={}'.format(i) 193 html = get_page(start_url) 194 if html: 195 find_tr = re.compile('<tr>(.*?)</tr>', re.S) 196 trs = find_tr.findall(html) 197 for s in range(1, len(trs)): 198 find_ip = re.compile('<td>(\d+\.\d+\.\d+\.\d+)</td>') 199 re_ip_address = find_ip.findall(trs[s]) 200 find_port = re.compile('<td>(\d+)</td>') 201 re_port = find_port.findall(trs[s]) 202 for address, port in zip(re_ip_address, re_port): 203 address_port = address + ':' + port 204 yield address_port.replace(' ', '') 205 206 def crawl_iphai(self): 207 start_url = 'http://www.iphai.com/' 208 html = get_page(start_url) 209 if html: 210 find_tr = re.compile('<tr>(.*?)</tr>', re.S) 211 trs = find_tr.findall(html) 212 for s in range(1, len(trs)): 213 find_ip = re.compile('<td>\s+(\d+\.\d+\.\d+\.\d+)\s+</td>', re.S) 214 re_ip_address = find_ip.findall(trs[s]) 215 find_port = re.compile('<td>\s+(\d+)\s+</td>', re.S) 216 re_port = find_port.findall(trs[s]) 217 for address, port in zip(re_ip_address, re_port): 218 address_port = address + ':' + port 219 yield address_port.replace(' ', '') 220 221 def crawl_89ip(self): 222 start_url = 'http://www.89ip.cn/apijk/?&tqsl=1000&sxa=&sxb=&tta=&ports=&ktip=&cf=1' 223 html = get_page(start_url) 224 if html: 225 find_ips = re.compile('(\d+\.\d+\.\d+\.\d+:\d+)', re.S) 226 ip_ports = find_ips.findall(html) 227 for address_port in ip_ports: 228 yield address_port 229 230 def crawl_data5u(self): 231 start_url = 'http://www.data5u.com/free/gngn/index.shtml' 232 headers = { 233 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 234 'Accept-Encoding': 'gzip, deflate', 235 'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7', 236 'Cache-Control': 'max-age=0', 237 'Connection': 'keep-alive', 238 'Cookie': 'JSESSIONID=47AA0C887112A2D83EE040405F837A86', 239 'Host': 'www.data5u.com', 240 'Referer': 'http://www.data5u.com/free/index.shtml', 241 'Upgrade-Insecure-Requests': '1', 242 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36', 243 } 244 html = get_page(start_url, options=headers) 245 if html: 246 ip_address = re.compile('<span><li>(\d+\.\d+\.\d+\.\d+)</li>.*?<li class=\"port.*?>(\d+)</li>', re.S) 247 re_ip_address = ip_address.findall(html) 248 for address, port in re_ip_address: 249 result = address + ':' + port 250 yield result.replace(' ', '') 251 252 obj = Crawler() 253 print(obj.__doc__, '\n') 254 for i in dir(obj): 255 print(i) 256 257 ''' 258 __module__ __main__ 259 get_proxies <function Crawler.get_proxies at 0x00000000010D6620> 260 crawl_kxdaili <function Crawler.crawl_kxdaili at 0x00000000010D6840> 261 crawl_data5u <function Crawler.crawl_data5u at 0x00000000010D6C80> 262 crawl_89ip <function Crawler.crawl_89ip at 0x00000000010D6BF8> 263 crawl_goubanjia <function Crawler.crawl_goubanjia at 0x00000000010D6730> 264 __CrawlFunc__ ['crawl_kxdaili', 'crawl_data5u', 'crawl_89ip', 'crawl_goubanjia', 'crawl_iphai', 'crawl_xicidaili', 'crawl_premproxy', 'crawl_proxy360', 'crawl_ip3366', 'crawl_kuaidaili', 'crawl_ip181', 'crawl_xroxy'] 265 __CrawlFuncCount__ 12 266 crawl_iphai <function Crawler.crawl_iphai at 0x00000000010D6B70> 267 crawl_xicidaili <function Crawler.crawl_xicidaili at 0x00000000010D6A60> 268 crawl_premproxy <function Crawler.crawl_premproxy at 0x00000000010D68C8> 269 crawl_proxy360 <function Crawler.crawl_proxy360 at 0x00000000010D66A8> 270 crawl_ip3366 <function Crawler.crawl_ip3366 at 0x00000000010D6AE8> 271 crawl_kuaidaili <function Crawler.crawl_kuaidaili at 0x00000000010D69D8> 272 crawl_ip181 <function Crawler.crawl_ip181 at 0x00000000010D67B8> 273 __qualname__ Crawler 274 crawl_xroxy <function Crawler.crawl_xroxy at 0x00000000010D6950> 275 None 276 277 __CrawlFuncCount__ 278 __CrawlFunc__ 279 __class__ 280 __delattr__ 281 __dict__ 282 __dir__ 283 __doc__ 284 __eq__ 285 __format__ 286 __ge__ 287 __getattribute__ 288 __gt__ 289 __hash__ 290 __init__ 291 __le__ 292 __lt__ 293 __module__ 294 __ne__ 295 __new__ 296 __reduce__ 297 __reduce_ex__ 298 __repr__ 299 __setattr__ 300 __sizeof__ 301 __str__ 302 __subclasshook__ 303 __weakref__ 304 crawl_89ip 305 crawl_data5u 306 crawl_goubanjia 307 crawl_ip181 308 crawl_ip3366 309 crawl_iphai 310 crawl_kuaidaili 311 crawl_kxdaili 312 crawl_premproxy 313 crawl_proxy360 314 crawl_xicidaili 315 crawl_xroxy 316 get_proxies 317 '''
1 class MyType(type): 2 3 def __call__(cls, *args, **kwargs): 4 print('cls in __call__', cls) 5 print('in MyType __call__') 6 return type.__call__(cls, *args, **kwargs) 7 8 def __new__(cls, *args, **kwargs): 9 print('MyType__new__') 10 print('cls in __new__:', cls) 11 return type.__new__(cls, *args, **kwargs) # 也可写成:return type.__new__(MyType, *args, **kwargs) 12 13 14 class Foo(metaclass=MyType): # metaclass指定元类 15 16 def __init__(self): 17 self.name = 123 18 19 def f1(self): 20 print(self.name) 21 22 23 obj = Foo() # Foo是type元类创建的类对象,Foo()执行type的__call__方法 24 print(obj) 25 print(obj.name) 26 # 输出: 27 MyType__new__ 28 cls in __new__: <class '__main__.MyType'> 29 cls in __call__ <class '__main__.Foo'> 30 in MyType __call__ 31 <__main__.Foo object at 0x000000000104FF28> 32 123
1 class MyType(type): 2 3 def __call__(cls, *args, **kwargs): # cls:当前创建的类对象名字,即:Foo 4 obj = cls.__new__(cls, *args, **kwargs) # Foo是在这里,__new__创建的 5 print('&'*10) 6 obj.__init__(*args, **kwargs) 7 return obj 8 9 10 class Foo(metaclass=MyType): # metaclass指定这个Foo由谁创建(默认由type创建) 11 12 def __init__(self, name): 13 self.name = name 14 15 def f1(self): 16 print(self.name) 17 18 19 obj = Foo(123) # Foo是type的对象,Foo(123)执行type的__call__方法 20 print(obj) 21 print(obj.name) 22 23 # 输出: 24 &&&&&&&&&& 25 <__main__.Foo object at 0x0000000000A3F748> 26 123
组合:
1 class MyType(type): 2 def __call__(cls, *args, **kwargs): 3 4 obj = cls.__new__(cls, *args, **kwargs) 5 print('cls', cls) 6 print(obj, 123124214) 7 if type(obj) == Foo: 8 print(11111) 9 else: 10 print(222222) 11 print("========先======") 12 # 如下两种 可以在写这个之前 做一些操作,比如判断是什么类,传入什么参数等待等。 13 # cls.__init__(obj,*args,**kwargs) 14 obj.__init__(*args, **kwargs) 15 return obj 16 17 18 class Foo(metaclass=MyType): 19 def __init__(self, name): 20 print("========后======") 21 self.name = name 22 23 def f1(self): 24 print(self.name) 25 26 27 obj = Foo(123) 28 obj.f1() 29 # 输出: 30 # cls <class '__main__.Foo'> 31 # <__main__.Foo object at 0x00000000006EF748> 123124214 32 # 11111 33 # ========先====== 34 # ========后====== 35 # 123 36 37 # ''' 38 # 这里需要注意的:类是有type实例化的,一次类也是一个type类的对象。 而对象加括号,调用类的call方法,因此,下面的Foo(123) ,由于Foo是 39 # type类的实例化对象,因此Foo(123)会调用type的 __call__方法。 因此 args内有我们的传参123 40 # 所以cls是一个类名, 而call方法会调用Foo方法中的__new__方法,返回object.__new__ 赋值给obj 就是下面的obj 41 # 而接下来执行Foo.__init__ 42 # '''
依赖注入 利用类创建的
1 # # 实现 依赖注入 多层调用不用传参的方式 2 class Mapper: 3 4 __mapper_dict = {} 5 6 @staticmethod 7 def register(cls,vlaues): 8 Mapper.__mapper_dict[cls] = vlaues 9 10 @staticmethod 11 def exists(cls): 12 if cls in Mapper.__mapper_dict: 13 return True 14 return False 15 16 @staticmethod 17 def get_value(cls): 18 return Mapper.__mapper_dict[cls] 19 20 21 class MyType(type): 22 def __call__(cls, *args, **kwargs): 23 24 obj = cls.__new__(cls,*args,**kwargs) 25 26 arg_list = list(args) 27 if Mapper.exists(cls): 28 arg_list.append(Mapper.get_value(cls)) 29 30 # 如下两种 可以在写这个之前 做一些操作,比如判断是什么类,传入什么参数等待等。 31 #cls.__init__(obj,*args,**kwargs) 32 obj.__init__(*arg_list,**kwargs) 33 return obj 34 35 36 37 class Foo(metaclass=MyType): 38 def __init__(self,name): 39 self.name = name 40 def f1(self): 41 print(self.name) 42 class Bar(metaclass=MyType): 43 def __init__(self,name): 44 self.name = name 45 def f1(self): 46 print(self.name) 47 48 Mapper.register(Foo,"foo") 49 Mapper.register(Bar,"bar") 50 51 obj = Foo() 52 obj.f1() 53 obj = Bar() 54 obj.f1()
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
1 class Mapper: 2 __mapper_dict = {} 3 4 @staticmethod 5 def register(cls, vlaues): 6 Mapper.__mapper_dict[cls] = vlaues 7 8 @staticmethod 9 def exists(cls): 10 if cls in Mapper.__mapper_dict: 11 return True 12 return False 13 14 @staticmethod 15 def get_value(cls): 16 return Mapper.__mapper_dict[cls] 17 18 19 class MyType(type): 20 def __call__(cls, *args, **kwargs): 21 obj = cls.__new__(cls, *args, **kwargs) 22 23 arg_list = list(args) 24 if Mapper.exists(cls): 25 arg_list.append(Mapper.get_value(cls)) 26 27 # 如下两种 可以在写这个之前 做一些操作,比如判断是什么类,传入什么参数等待等。 28 # cls.__init__(obj,*args,**kwargs) 29 obj.__init__(*arg_list, **kwargs) 30 return obj 31 32 33 class Testt: 34 def __init__(self): 35 pass 36 37 38 class Foo(metaclass=MyType): 39 def __init__(self, t): 40 self.t = t 41 42 def f1(self): 43 print(self.name) 44 45 46 class Bar(metaclass=MyType): 47 def __init__(self, f): 48 self.f = f 49 50 def f1(self): 51 print(self.name) 52 53 54 Mapper.register(Foo, Testt()) 55 Mapper.register(Bar, Foo()) 56 57 b = Bar() 58 print(b.f.t) 59 60 # 输出:<__main__.Testt object at 0x00000000010941D0>
五 程序设计原则
1 # 单一责任原则SRP 2 # 一个对象只应该为一个元素服务: 比如你的数据库增删改查难道要放到多个类? 3 4 # 开放封闭原则:OCP 5 # 对于 装饰器,对内是封闭的,对外可以扩展 6 # 对于一个源码方法比如str类,它的源码我们尽量不改,我们用setattr(str,"k1",函数名) 这就实现了对外扩展该类 7 #其他语言叫extent 8 9 10 # 里氏替换原则:LSP 11 # 可以用任何派生类替换基类 12 13 # def (int i): # 可以是任何int的派生类 14 #print(i) 15 16 #其他语言必须制定类型 可以是这个类型的任何派生类 17 18 19 #接口分离原则ISP 20 #对于接口进行分类,避免一个方法过多 21 # 比如对于两个接口类 : 猫类(方法:喵喵叫 爬树) 狗类(方法:汪汪叫 摇尾巴) 这样我们继承接口类,进行约束只需要实现对应的就行。 22 #而如果这几个方法都写在一个接口类,那我们不需要用的方法也需要在派生类中实现。 23 24 25 # 依赖倒置原则 DIP 26 #http://blog.csdn.net/zhengzhb/article/details/7289269 27 """ 28 定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。 29 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。 30 解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。 31 依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。 32 """ 33

浙公网安备 33010602011771号