十天学会Python——第10天:Web服务器、闭包与装饰器

1 静态Web服务器

搭建Python自带的Web服务器:使用 python3 -m http.server 端口号(默认8000)

返回固定页面数据开发步骤:

1 编写一个TCP服务端程序

2 获取浏览器发送的HTTP请求报文数据

3 读取固定页面数据,把页面数据组装成HTTP响应报文数据发送给浏览器

4 HTTP响应报文数据发送完成以后,关闭服务于客户端的套接字

import socket

if __name__ == "__main__":
    # 1 编写一个TCP服务端程序
    tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)	# 创建socket
    tcp_server_socket.setsockopt(socket.SOLSOCKET,socket.SO_RESUEADDR,True)		# socket复用
    tcp_server_socket.bind(("",8080))		# 绑定地址
    tcp_server_socket.listen(128)		# 设置监听
    
    while True:
        # 2 获取浏览器发送的HTTP请求报文数据
        client_socket,client_addr = tcp_server.accept()	# 建立链接
        client_request_data = client_socket.recv(1024)decode()	# 获取浏览器请求信息
        print(client_request_data)
        # 3 读取固定页面数据,把页面数据组装成HTTP响应报文数据发送给浏览器
        with open("./static/index.html","rb") as f:
            file_data = f.read
        
        response_line = "HTTP/1.1 200 OK\r\n"
        response_header = "Sercer:pwb\r\n"
        response_body = file_data
        
        response_data = (response_line + response_header + "\r\n")
        client_socket.send(response_data)	# 发生数据
        
        # 4 HTTP响应报文数据发送完成以后,关闭服务于客户端的套接字
        cline_socket.close()

注意:

with expression as variableexpression是一个返回上下文管理器的表达式,variable用于保存上下文管理器返回的对象

返回指定页面数据开发步骤:

1 获取用户请求资源的路径

2 根据请求资源的路径,读取指定文件的数据

3 组装指定文件数据的响应报文,发送给浏览器

4 判断请求的文件在服务端不存在,组装404状态的响应报文,发送给浏览器

import socket

if __name__ == "__main__":
    # 1 编写一个TCP服务端程序
    tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)	# 创建socket
    tcp_server_socket.setsockopt(socket.SOLSOCKET,socket.SO_RESUEADDR,True)		# socket复用
    tcp_server_socket.bind(("",8080))		# 绑定地址
    tcp_server_socket.listen(128)		# 设置监听
    
    while True:
            # 2 获取浏览器发送的HTTP请求报文数据
            client_socket,client_addr = tcp_server.accept()	# 建立链接
            client_request_data = client_socket.recv(1024)decode()	# 获取浏览器请求信息
            print(client_request_data)

            # 获取用户请求资源的路径
            request_data = client_request_data.split(" ")	# 返回的是一个列表
            request_path = request_data[1]

            if request_path == "/":
                request_path = "/index.html"

            # 3 读取固定页面数据,把页面数据组装成HTTP响应报文数据发送给浏览器
            # 根据请求资源路径,获取指定文件的数据
            try:
                with open("./static" + request_path,"rb") as f: 	# 这里是用户输入路径
                    file_data = f.read
            except Exception as e:
                # 返回404错误数据
                response_line = "HTTP/1.1 404 Not Found\r\n"
                response_header = "Sercer:pwb\r\n"
                response_body = "404 Not Found sorry"

                # 组装指定文件数据的响应报文,发送给浏览器
                response_data = (response_line + response_header + "\r\n" + response.body).encode
                client_socket.send(response_data)	# 发生数据

            else:
                response_line = "HTTP/1.1 200 OK\r\n"
                response_header = "Sercer:pwb\r\n"
                response_body = file_data

                # 组装指定文件数据的响应报文,发送给浏览器
                response_data = (response_line + response_header + "\r\n").emcode() + response.body
                client_socket.send(response_data)	# 发数据
            finally:
                # 4 HTTP响应报文数据发送完成以后,关闭服务于客户端的套接字
                cline_socket.close()

静态Web服务器—多任务版

当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞

import socket
import threading

def handle_client_request(client_socket):
    client_request_data = client_socket.recv(1024)decode()	# 获取浏览器请求信息
        print(client_request_data)
        
        # 获取用户请求资源的路径
        request_data = client_request_data.split(" ")	# 返回的是一个列表
        request_path = request_data[1]
        
        # 判断客户端是否关闭
        if len(request_data) == 1:
            client_socket.close()
            return
        
        if request_path == "/":
            request_path = "/index.html"
        
        # 3 读取固定页面数据,把页面数据组装成HTTP响应报文数据发送给浏览器
        # 根据请求资源路径,获取指定文件的数据
        try:
            with open("./static" + request_path,"rb") as f: 	# 这里是用户输入路径
                file_data = f.read
        except Exception as e:
            # 返回404错误数据
            response_line = "HTTP/1.1 404 Not Found\r\n"
            response_header = "Sercer:pwb\r\n"
            response_body = "404 Not Found sorry"

            # 组装指定文件数据的响应报文,发送给浏览器
            response_data = (response_line + response_header + "\r\n" + response.body).encode
            client_socket.send(response_data)	# 发生数据
                
        else:
            response_line = "HTTP/1.1 200 OK\r\n"
            response_header = "Sercer:pwb\r\n"
            response_body = file_data

            # 组装指定文件数据的响应报文,发送给浏览器
            response_data = (response_line + response_header + "\r\n").emcode() + response.body
            client_socket.send(response_data)	# 发数据
        finally:
            # 4 HTTP响应报文数据发送完成以后,关闭服务于客户端的套接字
            cline_socket.close()
            
if __name__ == "__main__":
    # 1 编写一个TCP服务端程序
    tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)	# 创建socket
    tcp_server_socket.setsockopt(socket.SOLSOCKET,socket.SO_RESUEADDR,True)		# socket复用
    tcp_server_socket.bind(("",8080))		# 绑定地址
    tcp_server_socket.listen(128)		# 设置监听
    
    while True:
            # 2 获取浏览器发送的HTTP请求报文数据
            client_socket,client_addr = tcp_server.accept()	# 建立链接

            # 创建子线程
            sub_thread = threading.Thread(target=handler_client_request,args=(client_socket,))
            sub_thread.start()

静态Web服务器—面向对象开发

1 把提供服务的Web服务器抽象成一个类(HTTPWebServer):class HttpWebServer

2 提供Web服务器的初始化方法,在初始化方法里面创建Socket对象:def __init__(self)

3 提供一个开启Web服务器的方法,让Web服务器处理客户端请求操作:def star(self)

import socket
import threading
         
class HttpWebServer:
    def __init__(self):
        # 1 编写一个TCP服务端程序
        self. tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)	# 创建socket
        self. tcp_server_socket.setsockopt(socket.SOLSOCKET,socket.SO_RESUEADDR,True)		# socket复用
        self. tcp_server_socket.bind(("",8080))		# 绑定地址
        self. tcp_server_socket.listen(128)		# 设置监听
    
    def handle_client_request(self,client_socket):
    client_request_data = client_socket.recv(1024)decode()	# 获取浏览器请求信息
        print(client_request_data)
        
        # 获取用户请求资源的路径
        request_data = client_request_data.split(" ")	# 返回的是一个列表
        request_path = request_data[1]
        
        # 判断客户端是否关闭
        if len(request_data) == 1:
            client_socket.close()
            return
        
        if request_path == "/":
            request_path = "/index.html"
        
        # 3 读取固定页面数据,把页面数据组装成HTTP响应报文数据发送给浏览器
        # 根据请求资源路径,获取指定文件的数据
        try:
            with open("./static" + request_path,"rb") as f: 	# 这里是用户输入路径
                file_data = f.read
        except Exception as e:
            # 返回404错误数据
            response_line = "HTTP/1.1 404 Not Found\r\n"
            response_header = "Sercer:pwb\r\n"
            response_body = "404 Not Found sorry"

            # 组装指定文件数据的响应报文,发送给浏览器
            response_data = (response_line + response_header + "\r\n" + response.body).encode
            client_socket.send(response_data)	# 发生数据
                
        else:
            response_line = "HTTP/1.1 200 OK\r\n"
            response_header = "Sercer:pwb\r\n"
            response_body = file_data

            # 组装指定文件数据的响应报文,发送给浏览器
            response_data = (response_line + response_header + "\r\n").emcode() + response.body
            client_socket.send(response_data)	# 发数据
        finally:
            # 4 HTTP响应报文数据发送完成以后,关闭服务于客户端的套接字
            cline_socket.close()
    
    def star(self):
        while True:
            # 2 获取浏览器发送的HTTP请求报文数据
            client_socket,client_addr = self. tcp_server.accept()	# 建立链接
            # 创建子线程
            sub_thread = threading.Thread(target=self.handler_client_request,args=(client_socket,))
            sub_thread.start()
            
if __name__ == '__main__':
    # 创建服务器对象
    my_web_server = HttpWebServer()
    my_web_server.start()

静态Web服务器—命令行启动动态绑定端口号

1 获取执行python程序的终端命令行参数

2 判断参数的类型,设置端口号必须是整型

3 给Web服务器类的初始化方法添加一个端口号参数,用于绑定端口号

import socket
import threading
import sys
         
class HttpWebServer:
    def __init__(self,port):
        # 1 编写一个TCP服务端程序
        self. tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)	# 创建socket
        self. tcp_server_socket.setsockopt(socket.SOLSOCKET,socket.SO_RESUEADDR,True)		# socket复用
        self. tcp_server_socket.bind(("",port))		# 绑定地址
        self. tcp_server_socket.listen(128)		# 设置监听
    
    def handle_client_request(self,client_socket):
    client_request_data = client_socket.recv(1024)decode()	# 获取浏览器请求信息
        print(client_request_data)
        
        # 获取用户请求资源的路径
        request_data = client_request_data.split(" ")	# 返回的是一个列表
        request_path = request_data[1]
        
        # 判断客户端是否关闭
        if len(request_data) == 1:
            client_socket.close()
            return
        
        if request_path == "/":
            request_path = "/index.html"
        
        # 3 读取固定页面数据,把页面数据组装成HTTP响应报文数据发送给浏览器
        # 根据请求资源路径,获取指定文件的数据
        try:
            with open("./static" + request_path,"rb") as f: 	# 这里是用户输入路径
                file_data = f.read
        except Exception as e:
            # 返回404错误数据
            response_line = "HTTP/1.1 404 Not Found\r\n"
            response_header = "Sercer:pwb\r\n"
            response_body = "404 Not Found sorry"

            # 组装指定文件数据的响应报文,发送给浏览器
            response_data = (response_line + response_header + "\r\n" + response.body).encode
            client_socket.send(response_data)	# 发生数据
                
        else:
            response_line = "HTTP/1.1 200 OK\r\n"
            response_header = "Sercer:pwb\r\n"
            response_body = file_data

            # 组装指定文件数据的响应报文,发送给浏览器
            response_data = (response_line + response_header + "\r\n").emcode() + response.body
            client_socket.send(response_data)	# 发数据
        finally:
            # 4 HTTP响应报文数据发送完成以后,关闭服务于客户端的套接字
            cline_socket.close()
    
    def star(self):
        while True:
            # 2 获取浏览器发送的HTTP请求报文数据
            client_socket,client_addr = self. tcp_server.accept()	# 建立链接
            # 创建子线程
            sub_thread = threading.Thread(target=self.handler_client_request,args=(client_socket,))
            sub_thread.start()
            
def main():
    # 获取执行python程序的终端命令行参数
    print(sys.argv)
    if len(sys.argv) != 2:
        print('格式错误 pyhton3 xxx.py 9090')
        return
    # 判断参数的类型,设置端口号必须是整型
    if not sys.argv[1].isdigit():		# isdigit():判断参数是否为整型
        print('格式错误 pyhton3 xxx.py 9090')
        return
    # 创建服务器对象
    # 给Web服务器类的初始化方法添加一个端口号参数,用于绑定端口号
    my_web_server = HttpWebServer(port)
    my_web_server.start()
    
if __name__ == '__main__':
    main()

2 闭包

2.1 函数参数

函数名存放的是函数所在空间地址,函数名()执行函数名所存放空间地址中的代码
在这里插入图片描述

def func01():
    print('nihao')
def foo(func):
    func()
# 调用函数 参数就是函数func01
foo(func01)

闭包:在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包

def func_out(num1):		# 这就是一个闭包
    def func_inner(num2):
        num = num1 + num2
    return func_inner
f = func_out(10)	# 创建闭包实例
f(1)		# 返回结果是:11

注意:

1 通过f=func_out(10)创建闭包,实际上f() 等价于 内部函数func_inner(),即调用闭包相当于调用内部函数

2 利用 nonlocal 变量,可以修改外部函数的变量

def func_out(num1):		# 这就是一个闭包
    def func_inner(num2):
        nunlaocal num1	# 声明外部函数变量
        num1 = num2 + 10
    print(num1)
    dun_inner(10)
    print(num1)
        
    return func_inner
func_out(10)	# 返回结果是:10,20

3 装饰器

装饰器:在不改变原有函数的源代码的情况下,给函数增加新的功能,本质是闭包

装饰器语法糖用法:

def check(fn):
    def inner():
        print('登录验证...')
        fn()
    return inner
# 解释器遇到 @check 会立即执行comment = check(comment)
@check
def comment():		# 需要被装饰的函数
    print('发表评论')
# 使用装饰器装饰函数,增加一个登录功能
# comment = check(comment)
comment()	# 返回结果是:登录验证...发表评论

在这里插入图片描述

装饰器实现函数执行时间统计

import time
def get_time(fn):
    def inner():
        start = time.time()
        fn()
        end = time.time()
        print('时间:',end - start)
    return inner

@get_time
def func():		# 需要被装饰的函数
    for i in range(100000):
        print(i)

func()	# 返回结果是:时间:0.2xxs

带有参数的装饰器

def logging(fn):	# fn = sum_num
    def inner(a,b):
        fn(a,b)
    return inner	# sum_num = inner

@logging
def sun_num(a,b):		# 需要被装饰的函数
    result = a + b
    print(result)

sum_num(1,2)	# 返回结果是:3

装饰带有返回值的函数

def logging(fn):	# fn = sum_num
    def inner(a,b):
        result = fn(a,b)
        print(result)
    return inner	# sum_num = inner

@logging
def sun_num(a,b):		# 需要被装饰的函数
    result = a + b
    print(result)

result = sum_num(1,2)
print(result)		# 返回结果是:3

通用装饰器—装饰带有不定长参数的函数

def logging(fn):	# fn = sum_num
    def inner(*args,**kwargs):
        result = fn(*args,**kwargs)
        print(result)
    return inner	# sum_num = inner

@logging
def sun_num(*args,**kwargs):		# 需要被装饰的函数
    print(*args,**kwargs)

sum_num(1,2,3,age="18")

多个装饰器装饰一个函数

def check1(fn1):
    def inner1():
        print('登录验证1')
        fn1()
    return inner1

def check1(fn2):
    def inner2():
        print('登录验证1')
        fn2()
    return inner2

@check1
@check2

def comment():		# 需要被装饰的函数
    print('发表评论')

comment()	# 返回结果是:登录验证1 登录验证2 发表评论

带有参数的装饰器

def logging(flag):
    def decorator(fn):		# 外部函数只允许有fn一个参数
        def inner(num1,num2):
            if flag == "+":
                print('正在进行加法运算')
            elif flag == "-":
                print('正在进行减法运算')
            result = fn(num1,num2)
            return result
        return inner
    return decorator

@logging('+')		# 此处 + 是装饰器的参数
def add(a,b):
    print a + b
    
result = add(1,3)
print(result)

类装饰器

__call__方法:一个类里面一旦实现了__call__方法,那么这个类创建的对象就是一个可调用对象,可以像调用函数一样进行调用

class Check(object):
    def __call__(self,*args,**kwargs):
        print('我是call')
c = Check()
c()			# 返回结果是:我是call
class Check(object):
    def __init__(self,fn):	# fn = comment
        self.__fn = fn		# 私有属性
    def __call__(self,*args,**kwargs):
        print('登录')
        self.__fn()		# comment()
@Check	# comment= Ckeck(comment)
def comment:
    print('发表评论')
    
comment()

esult = add(1,3)
print(result)

类装饰器

__call__方法:一个类里面一旦实现了__call__方法,那么这个类创建的对象就是一个可调用对象,可以像调用函数一样进行调用

class Check(object):
    def __call__(self,*args,**kwargs):
        print('我是call')
c = Check()
c()			# 返回结果是:我是call
class Check(object):
    def __init__(self,fn):	# fn = comment
        self.__fn = fn		# 私有属性
    def __call__(self,*args,**kwargs):
        print('登录')
        self.__fn()		# comment()
@Check	# comment= Ckeck(comment)
def comment:
    print('发表评论')
    
comment()
  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值