Python进阶
一、闭包
在定义全局变量上,全局变量有被修改的风险,一个包中的变量可能被其他的模块修改,因此需要闭包
def outer(logo):
def inner(msg):
print(f"<{logo}>{msg}<{logo}>")
return inner # 将函数返回出去
fn1 = outer("黑马程序员") # fn1就是函数inner
fn1("hello")
#--------输出结果----------
<黑马程序员>hello<黑马程序员>
def outer(num1):
def inner(num2):
nonlocal num1 # 使用nonlocal关键字可以使内部函数修改外部函数
num1 += num2
print(num1)
return inner
fn = outer(10)
fn(10)
fn(10)
fn(10)
#--------输出结果----------
20
30
40
优点:
- 无需定义全局变量即可实现通过函数持续的访问、修改某个值
- 闭包使用的变量的所用于在函数内,难以被错误的调用修改
缺点:
- 由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存
二、设计模式
2.1 装饰器模式
装饰器是一种闭包,其功能就是izai不破坏目标函数原有的代码功能的前提下,为目标函数增加新功能
1、闭包写法
def outer(func):
def inner():
print("我睡觉了")
func()
print("我起床了")
return inner
def sleep():
import random
import time
print("睡眠中。。。。。")
s = random.randint(1, 5)
print(s)
time.sleep(s)
fn = outer(sleep)
fn()
#===========结果输出===========
我睡觉了
睡眠中。。。。。
4
我起床了
2、装饰器的快捷写法(语法糖)
def outer(func):
def inner():
print("我睡觉了")
func()
print("我起床了")
return inner
@outer
def sleep():
import random
import time
print("睡眠中。。。。。")
s = random.randint(1, 5)
print(s)
time.sleep(s)
sleep()
#==========结果输出============
我睡觉了
睡眠中。。。。。
3
我起床了
添加@注解的后面的参数是装饰器,即@符号和装饰函数和被装饰函数产生联系。即将被@标记的函数传入到@后面的函数中
2.2 单例模式
保证一个类只有一个实例,并提供一个访问它的全局访问点
1、创建
class StrTools:
pass
str_tool = StrTools()
2、使用
from strTools import str_tool
s1 = str_tool
s2 = str_tool
print(s1)
print(s2)
#==========结果输出============
<strTools.StrTools object at 0x01EAB310>
<strTools.StrTools object at 0x01EAB310>
2.3 工厂模式
当需要大量创建一个类的实例的是偶,可以使用工厂模式,即从ui安生的使用类的构造去创建对象的形式,迁移到基于共产提供的方法去创建对象的形式
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()
elif p_type == 't':
return Teacher()
factory = Factory()
work = factory.get_person('w')
student = factory.get_person('s')
teacher = factory.get_person('t')
三、多线程
创建方式:使用threading关键字
import threading
threading.Thread([group [,target[,name[,args [,kwargs]]]]])
#- group: 暂未使用,未来功能的预留函数
#- target: 执行的目标的任务名
#- args: 以元组的方式给执行任务传参
#- keargs: 以字典的方式给执行 的任务传参
#- name: 线程名,一般不需要设置
3.1 创建、启动线程
import time
import threading
def sing():
while True:
print("sing")
time.sleep(1)
def dance():
while True:
print("dance")
time.sleep(1)
if __name__ == '__main__':
# 创建线程1
sing_thread = threading.Thread(target=sing)
# 创建线程2
dance_thread = threading.Thread(target=dance)
# 启动线程
sing_thread.start()
dance_thread.start()
#==========结果输出============
sing
dance
dance
sing
sing
dance
singdance
3.2 传递参数
import time
import threading
def sing(msg):
while True:
print(msg)
time.sleep(1)
def dance(msg):
while True:
print(msg)
time.sleep(1)
if __name__ == '__main__':
# 创建线程1
sing_thread = threading.Thread(target=sing, args=("Im sing",)) # 字符串后加逗号表示元组
# 创建线程2
dance_thread = threading.Thread(target=dance, kwargs={"msg": "Im dance"})
# 启动线程
sing_thread.start()
dance_thread.start()
#==========结果输出============
Im sing
Im dance
Im dance
Im sing
Im sing
Im dance
四、网络编程
socket是进程之间通讯的工具,负责程序之间的网络数据传输
4.1 socket服务端
accept是一个阻塞方法
- socket对象:用来设置监听、连接信息
- accept对象:客户端的连接对象、客户端的地址信息
使用socket创建对象后,可以使用创建的对象获取出客户端的IP和端口
import socket
# 1、创建socket对象
socket_server = socket.socket()
# 2、绑定ip地址和端口
socket_server.bind(("localhost", 8888))
# 3、监听端口
socket_server.listen(1) # listen方法内接受一个参数,表示接受的连接数
# 4、等待客户端链接
result: tuple = socket_server.accept()
# accept方法返回的是二元元组(连接对象,客户端地址信息)
conn = result[0] # 客户端的连接对象
address = result[1] # 客户端的地址信息
# 可以通过 变量1,变量2 = socket_server.accept()的形式,直接接受二元元组的两个元素
# conn1, address1 = socket_server.accept()
# accept是一个阻塞方法
print(f"客户端信息是:{address}")
while True:
# 5、接受客户端信息,使用客户端和服务端的连接对象,
data: str = conn.recv(1024).decode("UTF-8")
# recv接受的参数是缓冲区大小,一般给1024
# recv方法返回的是一个字节数组,即bytes对象,不是字符串,可以使用decode进行解码
print(f"客户端的消息是:{data}")
# 6、发送消息,需要将字符串编码为字节数组对象
msg = input("请输入需要回复的消息:")
if msg == 'exit':
break
conn.send(msg.encode("UTF-8"))
# 7、关闭连接
conn.close()
socket_server.close()
4.2 socket客户端
import socket
# 1、创建socket对象
socket_client = socket.socket()
# 2、连接到服务端
socket_client.connect(("localhost", 8888))
while True:
# 3、发送消息
msg = input("请输入要给服务端的消息")
if msg == 'exit':
break
socket_client.send(msg.encode("UTF-8"))
# 4、接受返回消息
recv_data = socket_client.recv(1024) # 同样recv是阻塞的
print(f"服务端返回的消息是:{recv_data.decode('UTF-8')}")
# 5、关闭连接
socket_client.close()