day34 python 对象的特殊方法__setattr__() 进程 requests模块 bs4模块

day34 python 对象的特殊方法__setattr__() 进程 requests模块 bs4模块
 
一.面向对象简单补充
    1.给对象设置值的本质: 是__setattr__() 这句
class Foo(object):
    def __init__(self):
        self.name = "bajie"                     #默认自己的类中执行 __setattr__, 自己没有这个方法去object里去找
    def __setattr__(self, key, value):
        object.__setattr__(self,key,value)      #本质: name = 'bajie' 是父类的这个方法设置的
obj = Foo()
print(obj.name)
    2.当在自己类里有写 __setattr__()方法时, 用自己的
      当自己类中没有__setattr__()方法时,找父类的, 如下面例子中找的是 object.__setattr__()
class Foo(object):
    def __init__(self):
        self.name = 'bajie'                    #没设置上值,因为自己的__setattr__()里面没有语句
        object.__setattr__(self,'info',{})     #设置上了        
    def __setattr__(self, key, value):
        pass
obj = Foo()
print(obj.name)                                 #没设置上值,因为自己的__setattr__()里面没有语句
print(obj.info)                                 #设置上了
 
    3.原码里是这样操作的
class Foo(object):
    def __init__(self):
        object.__setattr__(self,'info',{})
    def __setattr__(self, key, value):
        self.info[key] = value
    def __getattr__(self, item):                
        return self.info[item]      
obj = Foo()
obj.bajie = 'wukong'
print(obj.bajie)                                #print(obj.info['bajie'])  实际上是这个
 
二.进程
    1.进程的写法(和线程是一样的)    (multi 多种, processing 处理)
        linux下 正常写就行,没问题
        windows下 的多进程要写在 __main__ 里面,才能正常运行
#linux下 这样写没问题
 
import multiprocessing
def task(arg):
    print(arg)
for i in range(10):
    p = multiprocessing.Process(target=task, args=(i,))
    p.start()
 
#windows下 的多进程要写在 __main__ 里面,才能正常运行
 
import multiprocessing
def task(arg):
    print(arg)
def run():
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,))
        p.start()
if __name__ == '__main__':
    run()
 
#以后的代码没有在windows上运行, 都是在linux, 因为liunux免费
 
    2.进程本身: 进程间数据不共享
import multiprocessing
data_list = []
def task(arg):
    data_list.append(arg)
    print(data_list)
def run():
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,))
        p.start()
if __name__ == '__main__':
    run()
 
>>>[2]                                                #每个进程创建属于自己的内存空间, 空间里有各自的 data_list 变量
[3]
[1]
[0]
[6]
[5]
[7]
[4]
[8]
[9]
 
    3.进程常用方法, 和线程使用一样(关键词类似)
p.join()/p.join(5)
p.deamon = True                                        #默认为False
 
p.name = 'process1'    
p = multiprocessing.current_process()    
print(p.name)    
print(p.ident)(和p.pid是一个值)
    4.进程的创建方法(两种)
        4.1.直接使用多进程模块: multiprocessing
import multiprocessing
 
def task(arg):
    print(arg)
def run():
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,))
        p.start()
if __name__ == '__main__':
    run()
 
        4.2.使用类的继承方式创建进程
import multiprocessing
class MyProcess(multiprocessing.Process):
    def run(self):
        print('当前进程', multiprocessing.current_process())
def run():
    p = MyProcess()
    p.start()
    p1 = MyProcess()
    p1.start()
if __name__ == '__main__':
    run()
 
三.进程之间的数据共享
    企业中基本用不到:这个是内存级别的, 一般大量数据不放到内存里, 而是放到redis和mysql里
    进程间数据本身不共享, 我就想让进程间数据共享
 
    用特殊的容器来实现(先介绍两种)
    1.数据共享方式一
        普通的队列不能实现: 普通queue不能做进程间的数据共享
            q = queue.Queue()                
        用特殊队列来实现: 多进程模块中的队列
            q = multiprocessing.Queue()
        linux下 完全没有问题, 正常使用多进程中的queue即可
        windows下, 要把queue当成参数传给函数才行
#linux下 完全没有问题: q = multiprocessing.Queue(),正常写
import multiprocessing
import time
q = multiprocessing.Queue()
def task(arg):
    q.put(arg)
def run():
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,))
        p.start()
    time.sleep(2)
if __name__ == '__main__':
    run()
    v = q.get()
    print(v)
    v = q.get()
    print(v)
 
#windows下, 要把queue当成参数传进去才行
import multiprocessing
import time
def task(arg, q):                                           #要把queue当成参数传进去才行
    q.put(arg)
if __name__ == '__main__':
    q = multiprocessing.Queue()
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,q,))
        p.start()
    time.sleep(2)
    while 1:
        v = q.get()
        print(v)
    2.数据共享方式二
        用特殊的dict来实现: 多进程中的字典
            dic = multiprocessing.Manager().dict()
        2.1.直接上windows下的运行代码
            当使用dict或socket通信, 最终都是写到了一个文件里
            有个问题: 当主进程执行完, 就会把公共"字典文件"释放掉, 子进程没有了这个字典文件就会报错
import multiprocessing
import time
def task(arg, dic):
    dic[arg] = 100
if __name__ == '__main__':
    m = multiprocessing.Manager()
    dic = m.dict()                               
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,dic,))
        p.start()
        p.join()                                 #方法一: 等子进程一个一个执行完, 我主进程才开始执行,但是这样进程就不能并发了
    #time.sleep(2)                               #方法二: 加延迟时间只能测试时用, 因为你不知道进程到底确切地执行了多长时间
    print(dic.values())                              
        2.2.如何解决上面的问题
            方法三: 加检测, 不停地检测子进程的存活状态, 当子进程全都终止,才退出检测程序
                p.is_alive()
#直接上windows下的运行代码
import multiprocessing
import time
def task(arg, dic):
    dic[arg] = 100
process_list = []
if __name__ == '__main__':
    dic = multiprocessing.Manager().dict()
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,dic,))
        p.start()
        process_list.append(p)
    while 1:
        count = 0
        for p in process_list:
            if not p.is_alive():
                count += 1
        if count == len(process_list):
            break
    print(dic)
    3.数据共享方式三
        进程间的数据共享依赖其他设备的软件(例如: redis, mysql)
        经常用到的是这个
 
四.进程锁 (和线程锁一毛一样)
import multiprocessing
import time
lock = multiprocessing.RLock()
def task(arg):
    print('bajie ai shuishui')
    lock.acquire()
    time.sleep(5)
    print(arg)
    lock.release()
if __name__ == '__main__':
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(i,))
        p.start()
 
五.进程池
    python3.3之后才有的, 如果2.x的版本要使用, 只要装相关的模块就行了   
    线程的个数没法判断, 但是进程数可以确定: 和cpu的个数一样即可
    和线程池一毛一样
        pool = ProcessPoolExecutor(5)
        def task(arg):pass
        pool.submit(task,i)
#直接上windows下的代码
import time
from concurrent.futures import ProcessPoolExecutor
def task(arg):
    time.sleep(2)
    print(arg)
if __name__ == '__main__':
    pool = ProcessPoolExecutor(5)
    for i in range(20):
        pool.submit(task,i)
 
 
五.requests模块,bs4模块
    与进程和线程无关,与io多路复用有关的两个模块
    装包: pip3 install requests 
          pip3 install beautifulsoup4
'''
重要的不是爬虫,而是下面这些:
    a.下面这个示例进程好还是线程好?
        线程好, 因为是下载, 是io密集型操作
    b.requests模块是做什么的
        模拟浏览器发送请求, 本质:创建socket客户端-连接-发送请求-接收请求-断开连接
    c.线程池或进程池  
        
'''
import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
 
def task(url):
    r1= requests.get(url=url,headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"}) 
    
                                                                              #模拟浏览器发送请求,内部建立socket连接,和服务端建立连接,
    #print(r1.content)                                                        #这个是字节
    #print(r1.text)                                                           #查看下载的文本
    soup = BeautifulSoup(r1.text, 'html.parser')                              #把文本加持html解释器
    div_con = soup.find('div',attrs={'class':'link-con'})
    #print(div_con)
    for item in div_con.find_all('div',attrs = {'class':'link-detail'}):
        title = item.find_all('a')
        title_url = item.find_all('bref')
        print(title,title_url)
def run():
    pool = ThreadPoolExecutor(5)
    for i in range(1,50):
        pool.submit(task,'https://dig.chouti.com/%s' % (i,))
if __name__ == '__main__':
    run()
 
 
 
 
 
 
 

猜你喜欢

转载自www.cnblogs.com/aiaii/p/12222838.html