12 深浅拷贝、内存管理和socket网络通信
12.1 深浅拷贝
from copy import copy, deepcopy
class Person(object):
def __init__(self, name, age=0, gender='女'):
self.name = name
self.age = age
self.gender = gender
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]},id:{id(self)}>'
class Dog():
def __init__(self,name,color):
self.name = name
self.color = color
def __repr__(self):
return str(self.__dict__)
p1 = Person('小明')
print(p1) # <'name': '小明', 'age': 0, 'gender': '女',id:2443466222224>
# 1.直接拷贝
p2 = p1
print(p2) # <'name': '小明', 'age': 0, 'gender': '女',id:2443466222224>
p2.name = '小花'
print(p1) # <'name': '小花', 'age': 0, 'gender': '女',id:2443466222224>
print(p2) # <'name': '小花', 'age': 0, 'gender': '女',id:2443466222224>
# 2.拷贝: 不管怎么拷贝都是复制原数据,产生新的数据,并且将新数据的地址返回
p3 = copy(p1)
p4 = deepcopy(p1)
print('p3:', p3) # p3: <'name': '小花', 'age': 0, 'gender': '女',id:2443466222560>
print('p4:', p4) # p4: <'name': '小花', 'age': 0, 'gender': '女',id:2443466223512>
# 3.浅拷贝和深拷贝的区别
p1 = Person('Tom0', 18, '男')
p1.dog = Dog('大黄', '黄色')
print('p1:', p1) # p1: <'name': 'Tom0', 'age': 18, 'gender': '男', 'dog': {'name': '大黄', 'color': '黄色'},id:2443466395152>
# 浅拷贝
p2 = copy(p1)
print('p2:', p2) # p2: <'name': 'Tom0', 'age': 18, 'gender': '男', 'dog': {'name': '大黄', 'color': '黄色'},id:2443466395488>
# 深拷贝
p2 = deepcopy(p1)
print('p2:', p2) # p2: <'name': 'Tom0', 'age': 18, 'gender': '男', 'dog': {'name': '大黄', 'color': '黄色'},id:2443466395432>
p2.dog.color = '绿色'
print(p1.dog.color) # 黄色
总结:
- 深浅拷贝都是对源对象的复制,占用不同的内存空间
- 如果源对象只有一级目录的话,源做任何改动,不影响深浅拷贝对象
- 如果源对象不止一级目录的话,源做任何改动,都要影响浅拷贝,但不影响深拷贝
- 序列对象的切片其实是浅拷贝,即只拷贝顶级的对象
12.2 内存管理
-
内存管理
python内存管理是自动化(指的是对堆上的内存进行管理)
-
内存开辟
只要需要保存数据的时候系统就会自动在堆上开辟空间保存数据。
注意:如果需要保存的数据是数字或者字符串,系统会先检查专门保存数字字符串中是否已经存在这个数据,如果存在直接返回之前的数据地址,不存在才会开辟新的内存去保存。 -
内存释放
Python中的每一个数据都有一个属性用来保存这个数据的引用个数(引用计数),当引用计数的值为0,那么设个数据就会自动销毁
12.3 socket网络通信
- socket
socket又叫套接字(实现通信的两个端(程序)就是套接字)
套接字有两种:服务器套接字(server)、客户端套接字(client)
- 服务器套接字
1)创建socket对象
socket 类有两个参数,一个是family,一个是type
family决定ip的类型(ipv4,ipv6),AF_INET
指的是ipv4,是默认的;AF_INET6
指的是ipv6
type决定传输类型(TCP,UDP),SOCK_STREAM
指的是TCP,是默认的;SOCK_DGRAM
指的是UDP
from socket import socket
server = socket()
2)绑定ip和端口
语法:套接字对象.bind((ip地址,端口))
ip地址 - 找到服务器对应的计算机,字符串
端口 - 区分计算机中不同的服务(服务指的是正在运行的程序),整数,范围065535(其中01023属于熟知端口)
server.bind(('10.7.184.109',8080))
3)监听
语法:服务器套接字.listen(数量)
数量 - 限定同一时间能处理的客户端最大数量
server.listen(512)
4)让服务器一直运行
recv(字节数) - 接收数据(字节数指一次能接收的最大的数据)
while True:
print('等待电话')
# 1)接收客户端的请求
connect, address = server.accept()
print('通信...')
# 2)接收消息
re_data = connect.recv(1024)
print(str(re_data, encoding='utf-8'))
# 3)发送消息
connect.send(bytes('HTTP/1.1 200 OK\r\n\r\n 你好', encoding='utf-8'))
- 客户端套接字
1)创建socket对象
from socket import socket
client = socket()
2)连接服务器
client.connect(('10.7.184.109',8080))
3)发送消息
字符串.encode()
- 将字符串转换为二进制数据
msg = '你好吗?吃了吗?'
client.send(msg.encode())
4)接收消息
字符串.decode()
- 将二进制数据转换为字符串
re_data = client.recv(1024)
print(re_data.decode())
- 持续套接字
上面的方法只能一次发送一段数据,所以采用死循环进行改善
- 服务器:
from socket import socket
server = socket()
server.bind(('10.7.184.109', 8080))
server.listen(512)
while True:
print('等待电话')
# 1)接收客户端的请求
connect, address = server.accept()
print('通信...')
while True:
# 2)接收消息
re_data = connect.recv(1024)
print(str(re_data, encoding='utf-8'))
if re_data.decode() == '拜拜':
break
# 3)发送消息
msg = input('>>>')
connect.send(bytes(msg, encoding='utf-8'))
if msg == '拜拜':
break
- 客户器
from socket import socket
server = socket()
server.bind(('10.7.184.109', 8080))
server.listen(512)
while True:
print('等待电话')
# 1)接收客户端的请求
connect, address = server.accept()
print('通信...')
while True:
# 2)接收消息
re_data = connect.recv(1024)
print(str(re_data, encoding='utf-8'))
if re_data.decode() == '拜拜':
break
# 3)发送消息
msg = input('>>>')
connect.send(bytes(msg, encoding='utf-8'))
if msg == '拜拜':
break