用户输入网址请求某网站的过程
浏览器本身是一个客户端,当你输入 URL 的时候:
1. 首先浏览器会去请求 DNS 服务器,通过 DNS 获取相应的域名对应的 IP
2. 然后通过 IP 地址找到 IP 对应的服务器后,要求建立 TCP 连接
3. 等浏览器发送完 HTTP Request(请求)包后,服务器接收到请求包之后才开始处理请求包
4. 服务器调用自身服务,返回 HTTP Response(响应)包
5. 客户端收到来自服务器的响应后开始渲染这个 Response 包里的主体(body)
6. 等收到全部的内容随后断开与该服务器之间的 TCP 连接。
HTTPS实现原理
简单理解,https过程为:
1. 客户端先获取服务端给的公钥
2. 然后客户端实时生成随机数
3. 通过公钥加密提交给服务端
4. 服务端使用私钥对数据进行解密,得到随机数【公钥只能加密数据,不能解密数据(非对称加密)】
5. 然后告知客户端已经得到随机数(临时密钥)
6. 最后数据传输均使用该随机数(临时密钥)进行传输
https请求过程图
问:那为什么不直接客户端使用公钥加密数据,服务端使用私钥解密数据呢?
一方面是因为效率问题:
非对称加密虽然安全,但效率太低。相反,对称加密虽然不够安全,但效率较高
所以https本质上,就是通过非对称加密交换密钥,最终使用密钥进行对称加解密数据
还有一方面就是:
如果直接使用公钥进行加密,一旦服务端的私钥泄露,那所有的通讯都将被解密,极其不安全
with字段
with 语句实现原理建立在上下文管理器之上,上下文管理器是一个实现 __enter__ 和 __exit__ 方法的类。
因此,在with后跟着的对象需要实现有__enter__和__exit__方法。
# 例子如下
class Test:
def __enter__(self):
return '调用__enter__'
def __exit__(self, exc_type, exc_val, exc_tb):
print('销毁,调用__exit__')
if __name__ == '__main__':
with Test() as t:
print(f'得到:{t}')
# 打印结果:
# 得到:调用__enter__
# 销毁,调用__exit__
单例模式
import threading
class Test:
_instance = None
# 加锁目的是考虑多线程并发的情况,简单版本的单例无需相关代码
_lock = threading.RLock()
def __new__(cls, *args, **kwargs):
if cls._instance:
return cls._instance
# 抢占锁,释放锁
# 没有实例时调用父类new方法创建实例并保存起来,有实例则直接返回
with cls._lock:
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
获取一个对象的私有属性
class Test:
def __init__(self):
self.a = 111
self.__b = 222
if __name__ == '__main__':
test = Test()
print(test.a)
# 私有属性不能直接获取,如果非要获取,要时使用下面的:“_类名属性名”方式来获取
# print(test.__b)
print(test._Test__b)
# 输出:
# 111
# 222
strip方法
用以移除字符串首尾指定的字符,默认值为空格或换行符
【注】只能移除字符串首尾,中间的并不能移除。传递参数时,移除首尾【包含的】字符
例:
strs = 'abbacabb'
print(strs.strip('ba'))
输出结果:c
列表拼接【+】和【extend】
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(a, c) # 使用加号【+】拼接,结果:[1, 2, 3] [1, 2, 3, 4, 5, 6],a不变,新生成的c为拼接后新列表
d = a.extend(b)
print(a, d) # 使用extend拼接,结果:[1, 2, 3, 4, 5, 6] None,a改变,a为拼接后的新列表,没有返回值
字符串拼接【+】和【join】
运算结果都一样,区别在于:
由于字符串是不可变对象,当使用“+”连接字符串的时候,每执行一次“+”操作都会申请一块新的内存。
然后复制上一个“+”操作的结果和本次操作的有操作符到这块内存空间中,所以用“+”连接字符串的时候会涉及内存申请和复制;
join在连接字符串的时候,首先计算需要多大的内存存放结果,然后一次性申请所需内存并将字符串复制过去。
在用"+"连接字符串时,结果会生成新的对象,而用join时只是将原列表中的元素拼接起来。
因此在连接字符串数组的时候会考虑优先使用join,join的效率优于直接相加。
python作用域
a = 1 # 全局作用域
def fn1():
b = 2 # 函数作用域
def fn2():
c = 3 # 局部作用域
print(max) # 内建作用域
python的魔法方法
# 创建实例相关
__new__ :创建实例最先执行
__init__ :new传递参数过来,初始化实例
__call__ :实例被调用时触发
__del__ :实例被销毁时触发
# 字符串相关
__str__ :返回字符串,可读
__repr__ :返回可以直接通过eval函数生成该实例的字符串
__doc__ :返回注释内容,函数也有注释内容
# 上下文管理
__enter__ :进入上下文时执行,设置环境、配置资源等
__exit__ :离开上下文时执行,释放资源、清理环境等
# 属性操作
__setattr__ :赋值操作触发,有则修改,没有则添加
__getattr__ :取值操作且没有值时,才会触发
__getattribute__ :只要【.】操作都触发,包括使用方法
__delattr__ :删除操作触发,没有报错
# []字典操作
__getitem__ :索引符号[]取值触发
__setitem__ :索引符号[]赋值触发
__delitem__ :索引符号删除触发
# 关系运算符
__gt__、__lt__ :大于、小于
__eq__ 、__ne__ :等于、不等于
__get__、__le__ :大于等于、小于等于
# 迭代对象
__iter__ :返回迭代对象(self)
__next__ :迭代返回下一个值
# 描述符
__get__ :获取属性,可以添加描述信息、操作等
__set__ :设置属性,可以添加描述信息、操作等
__delete__ :删除属性,可以添加描述信息、操作等