第九周
Day 31
TCP协议和UDP协议
区别 | TCP | UDP |
---|---|---|
可靠性 | 对方必须回复一个ack确认信息,才会将自己这端的数据从内存中删除 | 发送一条消息就会立即删除,不管对方是否接收到 |
有无连接 | 有连接 | 无连接 |
传输效率 | 效率慢 | 效率高 |
粘包问题 | 有 | udp协议称之为数据报协议,每次发送都是一个完整的数据报,一个发送唯一对应一个接收(无) |
基于UDP协议的套接字和TCP的区别
区别 | TCP | UDP |
---|---|---|
配置 | SOCK_STREAM | SOCK_DGRAM |
listen | 有 | 无 |
accept(建立连接) | 有 | 无 |
发送 | send | sendto |
接收 | recv | recvfrom |
空 | 不允许发空 | 允许发空 |
基于socketserver模块实现并发udp
# 并发
import socketserver
class MyRequestHandler(socketserver.BaseRequestHandler):
def handle(self): # 处理通信
data,server=self.request
server.sendto(data.upper(),self.client_address)
if __name__ == '__main__':
s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
s.serve_forever()
# 基础
from socket import *
import time
server = socket(AF_INET, SOCK_DGRAM)
server.bind(('127.0.0.1', 8080))
while True:
data, client_addr = server.recvfrom(1024)
time.sleep(10)
server.sendto(data.upper(), client_addr)
基于socketserver模块实现并发TCP
class MyRequestsHandler(socketserver.BaseRequestHandler):
def handle(self): # 处理通信
while True:
try:
data = self.request.recv(1024)
if len(data) == 0:break
self.request.send(data.upper())
except Exception:
break
self.request.close()
if __name__ == '__main__':
s = socketserver.ThreadingTCPServer(("127.0.0.1", 8080), MyRequestsHandler)
s.serve_forever()
并发主要是基于方法的使用。
Day 02
元类
控制类的产生(写底层代码时)
1、python中一切皆对象,包括类,
class Teacher:
def __init__(self,name ,age):
self.name = name
self.age = age
def teach(self):
print("我正在教书!")
teacher = Teacher("dota", 18) # 调用Teacher类 得到 对象teaccher
# 调用元类 得到 Teacher 类
print(type(teacher))
print(type(Teacher))
print(type(teacher.teach))
------------------------------------
>>> <class '__main__.Teacher'>
>>> <class 'type'>
>>> <class 'method'>
例子中`type(Teacher)`说明`Teacher`本身也是一个对象,可以将其赋值给其他对象,对其添加属性,将其作为函数参数传递等等。
结论:默认的元类是type
,默认情况下我们用class关键字定义的类都是由type产生的
那么class关键字都做了那些事情呢?
1、先拿到一个类名
class_name = 'Teacher'
2、然后拿到类的父类
class_bases = (object, )
根据多继承原则,这里设置为元组
3、在运行类体代码,将产生的名字放在名称空间中
class_dic = {}
class_body = """
def __init__(self,name ,age):
self.name = name
self.age = age
def teach(self):
print("我正在教书!")
"""
exec(class_body, {}, class_dic)
print(class_dic)
-----------------------------------------
>>>
4、调用元类(传入类的三大要素:类名、基类、类的名称空间)得到一个元类的对象,然后将元类的对象赋值给变量名Teacher就是我们用class自定义的哪个类
Teacher = type(class_name, class_bases, class_dic)
自定义元类
我们知道了类是通过type方法定义出来的,那么我们可不可以自己定义一个元类呢?答案是肯定的
class Mymeta(type): # 只有继承了type类的类才是自定义的元类
pass
这只是自定义元类的一个模板
自定义元类来控制Teacher类的产生,但是我们要给他定义一下规范,那么开始吧。
1、类名必须用驼峰体
2、至少继承一个父类
3、必须要有文件注释,并且注释内容不为空
import re
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
if not re.match("[A-Z]", class_name):
raise BaseException("必须使用驼峰体命名法!")
if len(class_bases) == 0:
raise BaseException("必须继承一个父类!")
doc = class_dic.get("__doc__") # 获取注释
if not (doc and len(doc.strip()) > 0):
# 注释为空 和 有注释,但是注释全部是空格
raise BaseException("必须要有注释,且注释不能为空!")
class Teacher(object, metaclass=Mymeta):
"""
注释不能为空!
"""
def __init__(self,name, age):
self.name = name
self.age = age
def teach(self):
print("我正在讲......")
自定义元类来控制Teacher类的调用
对象是否能被调用,取决于是否有
__call__
方法
此时我们的元类Mymeta有默认的__call__
方法的,那么我们给它定义一个
调用Teacher类做的事情:
- 先创建一个老师的空对象
- 调用老师类内的
__init__
方法,然后将老师的空对象连同括号内的参数的参数一同传给__init__
- 返回初始化好的老师对象
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
if not re.match("[A-Z]", class_name):
raise BaseException("必须使用驼峰体命名法!")
if len(class_bases) == 0:
raise BaseException("必须继承一个父类!")
doc = class_dic.get("__doc__") # 获取注释
if not (doc and len(doc.strip()) > 0):
# 注释为空 和 有注释,但是注释全部是空格
raise BaseException("必须要有注释,且注释不能为空!")
def __call__(self, *args, **kwargs):
# 创建一个老师的空对象
teacher_obj = object.__new__(self) # object类
# 调用老师类内的__init__函数,然后将老师的空对象连同括号内的参数一同传给__init__
self.__init__(teacher_obj, *args, **kwargs)
return teacher_obj
--------------------------------------------------------
注意这里的__call__
方法其实底层已经定义好了,我们自定义只是为他附加额外的功能,就像下面的私有属性。不定义其实也没有影响,不定义就是按照默认的功能实现
补充:如何将类的对象全部设为私有
通过覆盖实现属性私有
class Mymeta(type):
def __init__(self, class_name, class_base, class_dic):
if not re.match("[A-Z]", class_name):
raise BaseException("命名应该为驼峰体!")
if len(class_base) == 0:
raise BaseException("至少继承一个父类!")
doc = class_dic.get("__doc__")
if not (doc and len(doc.strip()) > 0):
raise BaseException("必须要有文件注释,并且注释内容不为空。")
# res = OldboyTeacher("egon", 18)
def __call__(self, *args, **kwargs):
# 1. 先创建一个老师的空对象
teacher_obj = object.__new__(self)
# 2.调用老师类内的 __init__函数,然后将老师的空对象连同括号内的参数的参数一同传给__init__
self.__init__(teacher_obj, *args, **kwargs)
# 2.1 获取对象的字典
# teacher_obj.__dict__
# 2.2 创建新的对象字典
# dic = {k:v for k,v in teacher_obj.__dict__}
# 2.3 将方法(k)设置为私有
# dic = {"_%s__%s"%(self.__name__, k):v}
# 2.4 将原来的字典覆盖
teacher_obj.__dict__ = {"_%s__%s" % (self.__name__, k): v for k, v in teacher_obj.__dict__}
# 3.将初始化好的老师对象赋值给变量名res
return teacher_obj
单例模式
单例是一种设计模式,应用该模式的类指挥生成一个示例,单个实例,永远指向一个对象,创建单例模式节约内存
创建单例模式的三种方法
1、基于@classmethod
class MySQL:
_instance = None # 初始化单例对象
def __init__(self, ip, port): # 自定义的ip和port
self.ip = ip
self.port = port
@classmethod # 类方法
def settings(cls):
if cls._instance: # 如果存在单例对象
pass 返回单例对象
else: # 没有的话使用自定义的ip和port
cls._instance = cls("127.0.0.1", 3306)
return cls._instance
# 这里因为需要两个不同的的ip所以 创建两个对象
my1 = MySQL("123.0.0.1", 3306)
my2 = MySQL("123.0.0.2", 3306)
print(my1, my2)
# 这里就直接使用默认的了
my3 = MySQL.settings()
my4 = MySQL.settings()
print(my3, my4)
---------------------------------
>>> <__main__.MySQL object at 0x00000255CDF0CFD0> <__main__.MySQL object at 0x00000255CDF0CF60> # 不同对象
>>> <__main__.MySQL object at 0x00000255CDF0CE10> <__main__.MySQL object at 0x00000255CDF0CE10> # 相同对象
我们来看看没有 _instance 会怎么样!
def settings(cls):
# if cls.__instance:
# pass
# else:
cls.__instance = cls("127.0.0.1", 3306)
return cls.__instance
my3 = MySQL.settings()
my4 = MySQL.settings()
---------------------------------
>>> <__main__.MySQL object at 0x000001B6C7B8DF98> <__main__.MySQL object at 0x000001B6C7B8DF60> # 不同
其实后面两种方法实现的原理是相通的
基于元类
class Mymeta(type):
_instance = None # 默认在类内加 _ 表示不想让外界访问
def __init__(self, class_name, class_bases, class_dic):
self._instance = object.__new__(self) # Mysql 类的对象
self.__init__(self._instance, "120.0.0.1", 3306)
def __call__(self, *args, **kwargs):
if args or kwargs: # 接受了参数
obj = object.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
else: # 没有接收参数 返回原对象
return self._instance
class MySQL(metaclass=Mymeta):
def __init__(self, ip, port):
self.ip = ip
self.port = port
my1 = MySQL("123.0.0.1", 3306)
my2 = MySQL("123.0.0.2", 3306)
print(my1, my2)
my3 = MySQL()
my4 = MySQL()
print(my3, my4)
--------------------------------
>>> <__main__.MySQL object at 0x0000023595A1DB38> <__main__.MySQL object at 0x0000023595A1DC18>
>>> <__main__.MySQL object at 0x0000023586A6F2B0> <__main__.MySQL object at 0x0000023586A6F2B0>
基于装饰器
def outter(func):
_instance = func("120.0.0.1", 3306)
def wrapper(*args, **kwargs):
if args or kwargs:
result = func(*args, **kwargs)
return result
else:
return _instance
return wrapper
@outter
class MySQL():
def __init__(self, ip, port):
self.ip = ip
self.port = port
my1 = MySQL("123.0.0.1", 3306)
my2 = MySQL("123.0.0.2", 3306)
print(my1, my2)
my3 = MySQL()
my4 = MySQL()
print(my3, my4)
-----------------------------------
>>> <__main__.MySQL object at 0x00000196906FEBA8> <__main__.MySQL object at 0x00000196906FEC88>
>>> <__main__.MySQL object at 0x00000196FFFDF278> <__main__.MySQL object at 0x00000196FFFDF278>
Day 03
猴子补丁
纯粹的替换,在使用模块之前替换,不能多次使用
许多代码都用到了json
模块,但是json
模块的dump
和load
功能太慢了,于是人们创建了性能更高的ujson
模块,那我们只要将原本的两个功能替换成ujson
的就好
import json
import ujson
json.load = ujson.load
json.dump = ujson.dump
# 封装一下
def monkey_patch_json():
json.__name__ = "ujson" # 重命名
json.load = ujson.load
json.dump = ujson.dump
monkey_patch_json() # 运行一下就能生效了
相对而言这种情况,比如自己创建了一个功能更丰富的模块,除了继承,我们也可以使用猴子补丁
在猴子补丁给我们带来便捷的同事,也有搞乱源代码优雅的风险。
内置函数
Builit-in function | ||||
---|---|---|---|---|
abs(x) | delattr(ojbect,name) | hash() | memoryview() | set() |
all(iterable) | dict() | help() | min() | setattr() |
any(iterable) | dir(object) | hex() | next() | slice() |
ascii(object) | divmod(a,b) | id() | object() | sorted() |
bin(x) | enumerate(iterable,start=0) | input() | oct() | staticmethod() |
bool(x) | eval() | int() | open() | str() |
breakpoint(*args,**kwargs) | exec() | isinstance() | ord() | sum() |
bytearray() | filter() | issubclass() | pow() | super() |
bytes() | float() | iter() | print() | tuple() |
callable() | format() | len() | property() | type() |
chr(i) | frozenset() | list() | range() | vars() |
@classmethod | getattr() | locals() | repr() | zip() |
compile() | globals() | map() | reversed() | __import__() |
[complex](返回值为real+imag*1j 的辅助,或将字符数字转换成复数) | hasattr() | max() | round() |
垃圾回收机制
并发编程
1、程序
程序就是一堆代码文件
2、进程
进程是一个抽象的概念
进程指的是程序的运行过程
3、操作系统
3.1 操作系统的作用
3.2 多道技术