1.闭包
(1)
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,则把这个使用外部函数的内部函数称为闭包
def outer(logo):
def inner(msg):
print(f"<{logo}>{msg}<{logo}>")
return inner
f = outer("*")
f("hello")
# output: <*>hello<*>
修改外部函数变量的值,需要使用nonlocal关键字修饰外部函数的变量,才可在内部函数中修改它
def outer(num1):
def inner(num2):
nonlocal num1
num1 += num2
print(num1)
return inner
f =outer(10)
f(10)
f(10)
# output:
# 20
# 30
eg:(atm)
def account_create(initial_amount=0):
def atm(num, deposit=True):
nonlocal initial_amount
if deposit:
initial_amount += num
print(f"存款:+{num},账户余额:{initial_amount}")
else:
initial_amount -= num
print(f"取款:-{num},账户余额:{initial_amount}")
return atm
fn = account_create()
fn(200)
fn(300)
fn(300, deposit=False)
# 存款:+200,账户余额:200
# 存款:+300,账户余额:500
# 取款:-300,账户余额:200
(2)优点:
·无需定义全局变量即可实现通过函数,持续的访问、修改某个值
·闭包使用的变量的所用于在函数内,难以被错误的调用修改
缺点:
·由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存
2.装饰器
(1)也是一种闭包,功能是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能
一般写法:
eg:在调用sleep前输出:我要睡觉了,调用后输出:结束
def sleep():
import random
import time
print("Zzz...")
time.sleep(random.randint(1,5))
def outer(func):
def inner():
print("我要睡觉了...")
func()
print("结束")
return inner
fn = outer(sleep)
fn()
# output:
# 我要睡觉了...
# Zzz...
# 结束
高级:
def outer(func):
def inner():
print("我要睡觉了...")
func()
print("结束")
return inner
@outer
def sleep():
import random
import time
print("Zzz...")
time.sleep(random.randint(1,5))
sleep()
# output:
# 我要睡觉了...
# Zzz...
# 结束
3、设计模式
设计模式就是一种编程套路,使用特定的套路得到特定的效果
(1)单例模式
就是对一个类,只获取其唯一的类实例对象,持续复用它
·节省内存
·节省创建对象的开销
class StrTools:
pass
str_tools = StrTools()
from test import str_tools
s1 = str_tools
s2 = str_tools
print(s1)
print(s2)
(2)工厂模式
将对象的创建由使用原生类本身创建,转换到由特定的工厂方法来创建
好处:
·大批量创建对象的时候有统一的入口,易于代码维护
·当发生修改,仅修改工厂类的创建方法即可
·符合现实世界的模式,即由工厂来制作产品(对象)
class Person:
pass
class Worker(Person):
pass
class Student(Person):
pass
class Teacher(Person):
pass
class Factory:
def get_person(self,p_type):
if p_type == 'w':
return Worker()
elif p_type == 's':
return Student()
else:
return Teacher()
factory = Factory()
worker = factory.get_person('w')
student = factory.get_person('s')
teacher = factory.get_person('t')
4、多线程并执行
(1)进程
程序在操作系统内运行,即成为一个运行进程
(2)线程
是进程的实际工作最小单位,进程内部可以有多个线程,程序的运行本质就是由进程内部的线程在实际工作的
(3)并行执行
·多个进程同时在运行,即不同的程序同时运行,称之为:多任务并行执行
·一个进程内的多个线程同时在运行,称之为:多线程并行执行
5、多线程编程
threading模块实现多线程
thread_obj =threading.Thread(target=func) 创建线程对象
thread_obj.start()启动线程执行
thread_obj = threading.Thread([group [,target [, name [,args [, kwargs]]]]]) - group: 暂时无用,未来功能的预留参数 - target:执行的目标任务名 - args:以元组的方式给执行任务传参 - kwargs:以字典的方式给执行任务传参 - name:线程名,一般不用设置
def sing():
while True:
print("Singing...")
time.sleep(1)
def dance():
while True:
print("Dancing...")
time.sleep(1)
if __name__ == '__main__':
sing()
dance()
# Singing...
# Singing...
# Singing...
# Singing...
# .....
则使用多线程后:
import threading
import time
def sing():
while True:
print("Singing...")
time.sleep(1)
def dance():
while True:
print("Dancing...")
time.sleep(1)
if __name__ == '__main__':
sing_thread = threading.Thread(target=sing)
dance_thread = threading.Thread(target=dance)
sing_thread.start()
dance_thread.start()
需要传参:
·args参数以元组的方式给执行任务传参
或kwargs参数以字典的方式给执行任务传参
import threading
import time
def sing(msg):
while True:
print(msg)
time.sleep(1)
def dance(msg):
while True:
print(msg)
time.sleep(1)
if __name__ == '__main__':
sing_thread = threading.Thread(target=sing, args=("Singing...",))
dance_thread = threading.Thread(target=dance, kwargs={ "msg": "Dancing..."})
sing_thread.start()
dance_thread.start()
6、Socket服务端开发
Socket服务端:等待其他进程的连接、可接受发来的信息、可回复消息
Socket客户端:主动连接服务器,可发送消息、可接受回复
主要步骤:
(1)创建socket对象
(2)绑定socket_server到指定IP和地址
(3)服务端开始监听端口
(4)接收客户端连接,获得连接对象
(5)客户端连接后,通过recv方法,接收客户端发送的消息
(6)通过conn(客户端当次连接对象),调用send方法可回复消息
(7)conn(客户端当次连接对象)和socket_server对象调用close方法,关闭连接
import socket
# 创建Socket对象
socket_server = socket.socket()
# 绑定IP地址和端口
socket_server.bind(("localhost", 8888))
#监听端口,listen()接受一个整数传参数,表示接受的链接数量
socket_server.listen(1)
# result: tuple = socket_server.accept()
# conn = result[0]
# address = result[1]
conn, address = socket_server.accept()
# accept返回的是二元元组(链接对象,客户端地址信息)
# 且是阻塞的方法,等待客户端的链接,若没有链接,就卡在这不执行了
print(f"接受客户端链接,客户端信息:{address}")
# recv返回值是一个字节数组,不是字符串,可以通过decode将字节数组转换为字符串
data: str = conn.recv(1024).decode("UTF-8")
# 接受客户信息,使用客户端和服务端的本次链接对象
print(f"客户端发来的消息是:{data}")
msg = input("请输入与客户端回复信息:").encode("UTF-8")
# encode将字符串转换为字节数组
conn.send(msg)
conn.close()
socket_server.close()
持续的消息:
import socket
socket_server = socket.socket()
socket_server.bind(("localhost", 8888))
#监听端口,listen()接受一个整数传参数,表示接受的链接数量
socket_server.listen(1)
# result: tuple = socket_server.accept()
# conn = result[0]
# address = result[1]
conn, address = socket_server.accept()
# accept返回的是二元元组(链接对象,客户端地址信息)
# 且是阻塞的方法,等待客户端的链接,若没有链接,就卡在这不执行了
print(f"接受客户端链接,客户端信息:{address}")
while True:
# recv返回值是一个字节数组,不是字符串,可以通过decode将字节数组转换为字符串
data: str = conn.recv(1024).decode("UTF-8")
# 接受客户信息,使用客户端和服务端的本次链接对象
print(f"客户端发来的消息是:{data}")
msg = input("请输入与客户端回复信息:")
# encode将字符串转换为字节数组
if msg =='exit':
break
conn.send(msg.encode("UTF-8"))
conn.close()
socket_server.close()
7、Socket客户端开发
主要步骤:
(1)创建socket对象
(2)连接到服务器
(3)发送消息
(4)接收返回消息
(5)关闭链接
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接服务器
socket_client.connect(("localhost", 8888))
# 发消息
socket_client.send("hello".encode("UTF_8"))
# 接收消息
recv_data = socket_client.recv(1024)
print(f"服务端回复消息:{recv_data.decode('UTF_8')}")
socket_client.close()
持续消息:
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接服务器
socket_client.connect(("localhost", 8888))
while True:
# 发消息
msg = input("请输入给服务端发送的消息:")
if msg == 'exit':
break
socket_client.send(msg.encode("UTF_8"))
# 接收消息
recv_data = socket_client.recv(1024)
print(f"服务端回复消息:{recv_data.decode('UTF_8')}")
socket_client.close()
先运行服务器端,再运行客户端:
主动客户端,被动服务器。