11月python学习

11月学习总结

单例模式

  • 只能创建一个对象
# 单例模式
class A:
    __isinstace = None

    def __init__(self):
        print('init')

    # __new__方法是为对象在内存中开辟内存空间,__init__是为该空间封装属性
    def __new__(cls, *args, **kwargs):
      print('new')
        if not cls.__isinstace:
            cls.__isinstace = super().__new__(cls)
        return cls.__isinstace


if __name__ == '__main__':
    a = A()
    aa = A()

    print(id(a))
    print(id(aa))

item系列

  • item的所有方法是以访问字典的方式访问对象的所有属性
  • attr的所有方法是以操作变量的方法操作对象的内部属性
  • 对于访问、更新、创建、删除不存在的属性时会调用attr相关的方法
class A:
    def __init__(self, v):
        self.v = v

    def __getitem__(self, key):
        print('getitem')

    def __setitem__(self, key, value):
        print('setitem')

    def __getattr__(self, key):
        print('getattr')

    def __setattr__(self, key, value):
        print('setattr')

    def __delitem__(self, key):
        print('delitem')

    def __delattr__(self, key):
        print('delattr')

if __name__ == '__main__':
    a = A(1)
    a['v'] = 1
    a.v = 2

    v = a.v
    vv = a['v']

    del a.v
    del a['v']

上下文管理

class A:
    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')
        return 1

    def __exit__(self, exception_type, exception_value, traceback):
        print('exit')


if __name__ == '__main__':
    # a 为__enter__方法返回的值
    with A() as a:
        print(a)

反射

首先获取目标的所有方法、属性集,然后再获取。

attr()方法就是通过参数获取相应对象中的值。

其中一个很重要的功能就是hasattr()和getattr(),因为python一切皆对象,所以说所有的属性和方法是以字典的形式保存的,即key-->value,键名对应着值。若要获取一个对象的属性的值,就是前往该对象的属性、方法集合中去寻找相应的键,若存在就返回值,否则就报错,若调用getattr就会做相应的错误处理(返回一句提示);若要更新一个对象中的值,则是前往属性、方法集合中去寻找相应的键,并更新值,若键不存在就更新集合,添加一个键,并默认为其赋予默认的值。

class A:
    def __init__(self, value):
        self.value = value



if __name__ == '__main__':
    a = A(1)
    if hasattr(a, 'b'):
        getattr(a, 'b')
    else:
        print('not find')

    print(getattr(a, 'b', 'not find'))


def func1():
    print('func1')

def fun2():
    print('func2')


# globals()获取当前文件中所有的方法和属性
# print(globals()['func1']())


import sys

# 获取当前主进程模块
obj = sys.modules['__main__']
print(obj.__dict__)

多进程

  • 单继承
    • 创建方法
      • 创建Process对象
      • 继承Process对象
        • 重写run方法,相当于是target的值,可以通过实现__init__,通过super().__init__()实现传入参数
  • 多进程
    • 创建
      • 多进程
        • 多次创建对象
      • 进程池
        • 列表存储
        • Pool对象存储
    • 进程间的通信
      • Queue是位于内存中的一个交换的之间的区域,用于存放两个进程之间需要公用的数据。
      • 进程池
        • Manager().Queue()
      • Queue()(使用方法与进程池的Queue类似,传入一个数据表示一次性最多可以缓存的消息数量)
      • 一般的锁
      • 死锁(各持一把对方都需要的锁)

python中由于GIL(全局解释锁)的存在,一次只能执行一个进程,并不能达到真正意义上的多进程

# 多进程
from multiprocessing import Process, Pool,Manager, Lock
import time

def func1():
    print('fucn1')

def func2():
    print('func2')


def func3(i):
    print('接收', i)
    time.sleep(1)
    print('结束', i)


def func3(queue, i, lock):
    lock.acquire()
    queue.put(f'放入{i}')
    print(f'成功放入{i}')
    time.sleep(2)
    lock.release()

def func4(queue):
    data = queue.get()
    print('拿出数据:', data)
    time.sleep(0.5)

class MyProcess(Process):
    def __init__(self, args):
        self.args = args
        super().__init__(target=self.run, args=args)
    def run(self):
        print('获取', self.args[0])
        time.sleep(1)
        print('结束', self.args[0])


if __name__ == '__main__':
    # p1 = Process(target=func1)
    # p2 = Process(target=func2)
    start = time.time()

    # 进程池
    # processes = [Process(target=func3, args=(i, )) for i in range(100)]

    # pool = Pool()
    # for i in range(100):
    #     pool.apply_async(func3, (i,))
    #
    # pool.close()
    # pool.join()

    # for p in processes:
    #     p.start()
    #
    # for p in processes:
    #     p.join()
    # p1.start()
    # p2.start()
    #
    # p1.join()
    # p2.join()

    # 继承实现
    # processes = [MyProcess(args=(i,)) for i in range(100)]
    # for p in processes:
    #     p.start()
    # for p in processes:
    #     p.join()


    # 进程间通信
    queue = Manager().Queue()
    lock = Lock()


    processes = [Process(target=func3, args=(queue, i, lock)) for i in range(50)]

    processes += [Process(target=func4, args=(queue,)) for _ in range(40)]

    for p in processes:
            p.start()

    for p in processes:
            p.join()

    # 锁


    end = time.time()
    print('主进程结束, 耗时:', end-start)

多线程

  • 进程是计算机分配资源的基本单位,线程是计算机执行的基本单位。
  • 线程必须存在于进程中。
  • 计算密集型任务用进程,I/O密集型用线程。
  • 线程的创建与进程的创建十分类似。
  • 线程的五种状态:
    • 创建
    • 就绪
    • 运行
    • 阻塞/睡眠/挂起
    • 死亡
# 多线程
from threading import Thread
import time
a = 0
def fun1():
    print('func1')

def fun2():
    print('func2')

def fun3():
    global a
    print('计算开始:', a)
    for i in range(1000000):
        a += 1
    print('计算结束:', a)

def func4():
    global a
    print('计算开始', a)
    for i in range(100000):
        a -= 1
    print('计算结果', a)
class MyThread(Thread):
    def run(self):
        print('MyThread')
        time.sleep(1)

if __name__ == '__main__':

    start = time.time()

    # 单线程
    # t1 = Thread(target=fun1)
    # t2 = Thread(target=fun2)
    #
    # t1.start()
    # t2.start()
    #
    # t1.join()
    # t2.join()

    # 多线程

    # threads = [MyThread() for _ in range(100)]
    #
    # for t in threads:
    #     t.start()
    # for t in threads:
    #     t.join()

    # 多线程通信, 以及多线程之间的并发所造成的数据有误

    threads = [Thread(target=fun3) for _ in range(100)]
    # threads += [Thread(target=func4) for _ in range(100)]




    for t in threads:
        t.start()

    for t in threads:
        t.join()

    end = time.time()

    print('最终结果:',a)
    print('耗时:', end-start)

信号量semaphore

表示同一时间内最多几个线程为就绪状态,准备被系统调度运行。

from threading import Thread, Semaphore
import time

def func1(i):
    s.acquire()
    print(f'开始执行{i}')
    time.sleep(1)
    print(f'结束行执行{i}')
    s.release()

if __name__ == "__main__":  

    start = time.time()  
    s = Semaphore(5)
    threads = [Thread(target=func1, args=(i, )) for i in range(100)]
    for t in threads:
        t.start()
    for i in threads:
        t.join()

    end = time.time()

    print('执行完成,耗时',end - start)

python程序的执行过程

  • 当执行python程序时,操作系统将程序和pythpn解释器加载到内存中,并开辟一块空间用于执行程序
  • python解释器分为编译器和虚拟机,首先编译器将python编译成C程序,然后虚拟机将C程序转换成字节码,然后输出机器码

同步锁

按照指定顺序执行程序即为同步,否则就为异步。

from threading import Thread, Lock
import time

def func1():
    while True:
        lock1.acquire()
        print('func1')
        time.sleep(0.5)
        lock2.release()


def func2():
    while True:
        lock2.acquire()
        print('func2')
        time.sleep(0.5)
        lock3.release()


def func3():
    while True:
        lock3.acquire()
        print('func3')
        time.sleep(0.5)
        lock1.release()


if __name__ == "__main__":

    lock1 = Lock()
    lock2 = Lock()
    lock2.acquire()
    lock3 = Lock()
    lock3.acquire()

    t1 = Thread(target=func1)

    t2 = Thread(target=func2)

    t3 = Thread(target=func3)

    t1.start()
    t2.start()
    t3.start()

网络编程

  • 一对一
    • tcp 安全,速率较慢
    • udp 快速,每次都是发送的数据包, 易数据丢失
    • tcp & udp
      • 面向连接和不面向连接
      • 占用系统资源
      • 数据流与数据报
      • tcp稳定,保证顺序性, udp可能丢包, 不保证顺序性
      • tcp --> send()/recv(), udp--> sendto(data, addr)/recvfrom()
  • 3次握手
    • 在tcp时,当执行connect()时,就会发生,首先客户端向服务端发送连接请求,服务段返回确认码atk和syn码,表示接收到请求,并告知客户端,客户端收到后返回确认码atk。
  • 4次挥手
    • 在tcp中,当执行close()时,若是客户端,则向服务端发送断开连接请求,服务端收到后响应,返回确认码,然后,服务端再发送消息告知客户端将要断开连接,客户端回应。
  • 全双工聊天室
    • 一对一
    • 一对多

一般步骤

  1. 导包
  2. 创建套接字
  3. 绑定地址和端口
  4. 监听/发送消息
  5. 关闭套接字

在OSI7层模型的4层模型中,应用层一下的都是由socket封装。

一对一

TCP

# tcp 服务端
from socket import *

# tcp
s = socket(AF_INET, SOCK_STREAM)
s.bind(('localhost', 9999))

s.listen()


new_socket = s.accept() # 返回的是一个套接字和客户端的ip+端口号
# socket, addr = new_socket
print(new_socket)
data = new_socket[0].recv(1024)
# socket.send(message.encode('utf-8'))
print(data[1][0])

if len(data) == 0: # 当客户端断开连接时会发送一个长度为0的数据,当检测到长度为0时,说明客户端已经断开连接p
    new_socket[0].close()

s.close()


# 客户端
from socket import *

s = socket(AF_INET, SOCK_STREAM)

s.connect(('localhost', 9999))
# 客户端请求连接,连接成功后就可以收发消息了
s.send('hhhhh'.encode('utf-8'))
s.recv(1024)
s.close()

UDP

# 服务端
from socket import *

s = socket(AF_INET, SOCK_DGRAM)

s.bind(('localhost', 9999))

data = s.recvfrom(1024)

print(data)

s.close()

# 客户端

s = socket(AF_INET, SOCK_DGRAM)

s.sendto('hhhh'.encode('utf-8'), ('localhost', 9999))

s.close()

全双工聊天室

一对一

from socket import *
from threading import Thread
import time

# 客户端/服务端(udp) 
class Send(Thread):
    def run(self):
        while True:
            data = input('>>>')
            s.sendto(data.encode('utf-8'), addr)
            time.sleep(0.5)

class Receive(Thread):
    def run(self):
        while True:
            data = s.recvfrom(1024)
            print(data[0].decode('utf-8'))
            time.sleep(0.5)
 

if __name__ =='__main__':

    s = socket(AF_INET, SOCK_DGRAM)

    addr = ('localhost', 9999)
    s.bind(('localhost', 8888))

    send = Send()
    rece = Receive()

    try:
        send.start()
        rece.start()
        send.join()
        rece.join()
    finally:
        s.close()

并发服务器

线程实现

from socket import *
from threading import Thread
import time

def deal_with_client(socket, addr):
    while True:
        data = socket.recv(1024)
        if len(data) == 0:
            break
        print(data.decode('utf-8'))
        time.sleep(0.5)
    socket.close()

if __name__ == '__main__':

    s = socket(AF_INET, SOCK_STREAM)
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 一般来说一个线程占用一个端口,通过设置这个使得多个线程可以访问同一个端口
    s.bind(('localhost', 8888))
    s.listen()
    while True:
        new_socket, new_addr = s.accept()
        p = Thread(target=deal_with_client, args=(new_socket, new_addr))  
        p.start()  
    s.close()
posted @ 2020-12-01 15:06  JonnyJiang-zh  阅读(79)  评论(0编辑  收藏  举报