Python基础:python的self是啥 附:含数据接收、解码和保存例子(基础)
python的self是啥
文章目录
- python的self是啥
- 前言:跟着伊希尔老师做python的数据接收、解码和保存
- 一、问题缘起:从self.socket-->socket是方法集合,那self是啥
- 是一个简化版的数据流例子
- 例子代码
- 二、解释self
- 2.1 解答:在 Python 中,`self` 是一个特殊的参数,它代表类的实例本身。
- 2.2 初步理解: 那就是类中的方法,有两个参数self和name(假设),此时可只传name参数,就能达到方法不同传参的同一个方法使用,约等于去掉self,这个方法实际参数只有一个name。如此理解就可以。
- 2.2.1 更深理解的例子辅助
- 2.2.2 学究式理解
- 三、回归socket的self理解:①代表实例 ②可以把 `self` 理解为 Java 中的 `this`
前言:跟着伊希尔老师做python的数据接收、解码和保存
最近跟着伊希尔老师做python的数据接收、解码和保存。由于首次使用python处理数据流,能大致理解方法作用,在具体到方法参数理解上却无法理解。我归结为对python惯例的未知导致的囫囵吞枣。这里举例我看不懂的socket对象创建及self到底是啥,进行自我理解。2024年10月30日11:51:07
一、问题缘起:从self.socket–>socket是方法集合,那self是啥
方法里,用socket对协议解析等。但socket方法前面一直跟着一个 self.socket ,但python却无参数类名体现,因为我得出疑问”self传进来是什么东西?是一个链接?一个数据?还是啥,而且java中用大写代表类型,小写代表对象。python中我不理解这个是啥意思“,具体例子如下
是一个简化版的数据流例子
简化版:
1、直接保存接收到的数据
2、简单的文件存储
3、基本的多线程处理
4、没有特定的数据格式要求
例子代码
import socket
import threading
import time
import os
# 基本配置
HOST = '0.0.0.0' # 监听所有网络接口
PORT = 9999 # 服务器端口号
SAVE_PATH = './data' # 数据保存路径
# 确保保存目录存在
os.makedirs(SAVE_PATH, exist_ok=True)
class SimpleDataSaver:
def __init__(self):
"""初始化数据保存器"""
self.current_file = None
def save_data(self, data, client_address):
"""保存数据到文件"""
# 用客户端地址创建文件名
filename = f"{SAVE_PATH}/{client_address[0]}-{client_address[1]}.txt"
# 如果文件未打开,打开它
if self.current_file is None:
self.current_file = open(filename, 'a')
# 保存数据和时间戳
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
self.current_file.write(f"{timestamp}: {data}\n")
self.current_file.flush() # 确保数据被写入磁盘
class SimpleTCPServer:
def __init__(self):
"""初始化服务器"""
# 创建TCP套接字
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 允许端口复用
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定地址和端口
self.server_socket.bind((HOST, PORT))
# 创建数据保存器
self.data_saver = SimpleDataSaver()
def handle_client(self, client_socket, client_address):
"""处理单个客户端连接"""
print(f"新的连接来自: {client_address}")
try:
while True:
# 接收数据
data = client_socket.recv(1024)
if not data:
break # 客户端断开连接
# 将收到的字节转换为字符串
data_str = data.decode('utf-8')
print(f"收到数据: {data_str}")
# 保存数据
self.data_saver.save_data(data_str, client_address)
# 发送确认消息
client_socket.send("数据已收到".encode('utf-8'))
except Exception as e:
print(f"处理客户端 {client_address} 时出错: {e}")
finally:
client_socket.close()
print(f"客户端 {client_address} 断开连接")
def start(self):
"""启动服务器"""
# 开始监听连接
self.server_socket.listen(5)
print(f"服务器正在监听 {HOST}:{PORT}")
try:
while True:
# 等待新的连接
client_socket, client_address = self.server_socket.accept()
# 为每个客户端创建新的线程
client_thread = threading.Thread(
target=self.handle_client,
args=(client_socket, client_address)
)
client_thread.daemon = True
client_thread.start()
except KeyboardInterrupt:
print("\n服务器正在关闭...")
finally:
self.server_socket.close()
# 启动服务器
if __name__ == '__main__':
server = SimpleTCPServer()
server.start()
二、解释self
2.1 解答:在 Python 中,self
是一个特殊的参数,它代表类的实例本身。
class Dog:
def __init__(self, name): # self 指向被创建的实例
self.name = name # 将 name 保存为实例的属性
def bark(self): # self 指向调用这个方法的实例
print(f"{self.name}: 汪汪!")
# 创建实例
dog1 = Dog("小黑") # Python 自动把创建的实例传给 self
dog2 = Dog("小白")
# 调用方法
dog1.bark() # 输出: 小黑: 汪汪!
dog2.bark() # 输出: 小白: 汪汪!
2.2 初步理解: 那就是类中的方法,有两个参数self和name(假设),此时可只传name参数,就能达到方法不同传参的同一个方法使用,约等于去掉self,这个方法实际参数只有一个name。如此理解就可以。
2.2.1 更深理解的例子辅助
class Student:
# 类变量(相当于 Java 中的 static 变量)
school_name = "Python大学"
def __init__(self, name, age):
"""
构造函数
self: 代表将来创建的实例本身
name, age: 参数
"""
# 实例变量(属性)- 每个实例都有自己的副本
self.name = name # self.name 是实例变量
self.age = age # self.age 是实例变量
self.courses = [] # 创建一个空列表来存储课程
def add_course(self, course):
"""
实例方法
self: 代表调用这个方法的实例
course: 参数
"""
self.courses.append(course)
print(f"{self.name} 添加了课程: {course}")
def show_info(self):
"""
实例方法:显示学生信息
"""
print(f"姓名: {self.name}")
print(f"年龄: {self.age}")
print(f"学校: {self.school_name}")
print(f"课程: {', '.join(self.courses)}")
@classmethod
def change_school(cls, new_name):
"""
类方法:修改学校名称
cls: 代表类本身(而不是实例)
"""
cls.school_name = new_name
print(f"学校名称已改为: {new_name}")
@staticmethod
def school_motto():
"""
静态方法:不需要访问类或实例的方法
"""
return "好好学习,天天向上"
# 使用示例
if __name__ == "__main__":
# 创建实例
print("=== 创建学生实例 ===")
student1 = Student("张三", 18) # Python自动将实例传给self
student2 = Student("李四", 19)
# 调用实例方法
print("\n=== 添加课程 ===")
student1.add_course("Python基础") # Python自动将student1传给self
student1.add_course("数据结构")
student2.add_course("算法导论")
# 显示信息
print("\n=== 显示学生1信息 ===")
student1.show_info()
print("\n=== 显示学生2信息 ===")
student2.show_info()
# 修改类变量
print("\n=== 修改学校名称 ===")
Student.change_school("新Python大学")
# 再次显示信息
print("\n=== 显示更新后的学生1信息 ===")
student1.show_info()
# 使用静态方法
print("\n=== 显示校训 ===")
print(Student.school_motto())
# 展示实例的内部结构
print("\n=== 实例的内部结构 ===")
print(f"student1的属性字典: {student1.__dict__}")
print(f"student2的属性字典: {student2.__dict__}")
2.2.2 学究式理解
这个例子展示了 Python 中类的几个重要概念:
-
self 作用
self
代表实例本身- 当你创建
student1 = Student("张三", 18)
时,Python 自动将student1
传给self
- 当你调用
student1.add_course("Python基础")
时,Python 自动将student1
传给self
-
不同类型的属性和方法:
- 实例变量(通过
self
访问):每个实例独有 - 类变量(所有实例共享):类似 Java 的 static 变量
- 实例方法(带
self
):需要访问实例属性的方法 - 类方法(带
@classmethod
):类似 Java 的 static 方法 - 静态方法(带
@staticmethod
):不需要访问实例或类的方法
- 实例变量(通过
-
Python 的命名规范:
- 类名用大写字母开头(如
Student
) - 变量和方法名用小写字母(如
name
,add_course
) - 但这只是规范,不是强制的(与 Java 不同)
- 类名用大写字母开头(如
三、回归socket的self理解:①代表实例 ②可以把 self
理解为 Java 中的 this
def __init__(self):
self.server_socket = socket.socket(...)
这里的含义是:
self
代表将来创建的服务器实例self.server_socket
是给这个实例创建一个 socket 属性- 每个服务器实例都有自己的 socket
当你创建服务器实例时:
server = SimpleTCPServer() # Python 自动将 server 传给 self
server.start() # Python 自动将 server 传给 self
你可以把 self
理解为 Java 中的 this
,但在 Python 中需要显式写出来作为第一个参数。