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__()函数;
demo

 

小结:

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
元类应用demo1
 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
demo2

 

 

 

组合:

 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>
依赖注入demo2

 

 

 

五 程序设计原则

 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  

 

 

posted @ 2018-05-02 13:15  whitesky-root  阅读(278)  评论(0)    收藏  举报