详解Python 记录、结构体和纯数据对象

  • Post category:Python

Python 记录、结构体和纯数据对象

Python 中有多种数据类型可以用来存储复杂的数据结构。在这些类型中,我们可以使用记录 (record)、结构体 (struct) 和纯数据对象 (plain data object) 来表示真实世界的实体或数据集合。

记录 (Record)

定义记录

在 Python 中,我们可以使用字典 (dictionary) 和命名元组 (namedtuple) 来定义记录。

使用字典时,我们可以将不同的属性作为键,将它们的值作为值,在一个字典中组织起来。

person = {
    "name": "Alice",
    "age": 28,
    "gender": "female",
    "email": "alice@example.com"
}

而对于有名的属性,我们可以使用命名元组来定义记录。命名元组是一个普通元组的子类,它的每个实例都可以像一个普通对象那样访问它的属性。

from collections import namedtuple

Person = namedtuple("Person", ["name", "age", "gender", "email"])

person = Person("Alice", 28, "female", "alice@example.com")

访问记录

对于字典,我们可以使用键来访问其中的值。

name = person["name"]

而对于命名元组,我们可以使用它的属性来访问其中的值。

name = person.name

结构体 (Struct)

定义结构体

结构体是一种将字节串拆分成一个有意义的序列的方法。在 Python 中,我们可以使用 struct 函数来定义和编码/解码结构体。对于不同的数据类型,需要使用不同的格式化字符串 (format string) 来定义它们。

import struct

# 定义格式化字符串
format_string = "<2ihd"

# 定义结构体
class Point:
    def __init__(self, x, y, is_visible, distance):
        self.x = x
        self.y = y
        self.is_visible = is_visible
        self.distance = distance

    def pack(self):
        # 编码数据
        return struct.pack(format_string, self.x, self.y, self.is_visible, self.distance)

    @classmethod
    def unpack(cls, data):
        # 解码数据
        x, y, is_visible, distance = struct.unpack(format_string, data)
        return cls(x, y, is_visible, distance)

编码/解码结构体

我们可以将一个结构体编码为二进制数据 (bytes),或者将二进制数据解码为一个结构体。

# 创建结构体
point = Point(1, 2, True, 3.14)

# 编码结构体
data = point.pack()

# 解码结构体
decoded_point = Point.unpack(data)

纯数据对象 (Plain Data Object)

定义纯数据对象

纯数据对象是一种与 Python 类无关的数据结构,它只由数据组成,没有任何行为。在 Python 中,我们可以使用 dataclass 来轻松定义纯数据对象。

from dataclasses import dataclass

@dataclass
class Rectangle:
    width: float
    height: float
    is_visible: bool = True

上面的代码定义了一个矩形对象,它由宽度、高度和是否可见属性构成。

使用纯数据对象

我们可以像使用普通对象那样来使用纯数据对象。

# 创建矩形对象
rectangle = Rectangle(3.0, 4.0)

# 修改矩形对象
rectangle.is_visible = False

# 访问矩形对象的属性
width = rectangle.width

示例说明

示例 1: 学生记录

假设我们要定义一个学生记录,它包含学生的姓名、年龄、所在地区和联系方式。我们可以用字典和命名元组来定义这个记录。

# 定义学生记录
student_dict = {
    "name": "Alice",
    "age": 18,
    "area": "Zhejiang",
    "contact": {
        "phone": "123456",
        "email": "alice@example.com"
    }
}

Student = namedtuple("Student", ["name", "age", "area", "contact"])

student_tuple = Student("Alice", 18, "Zhejiang", {"phone": "123456", "email": "alice@example.com"})

示例 2: 整数数组

假设我们要传输一个整数数组,我们可以使用结构体来编码和解码这个数组。

import struct

# 定义格式化字符串
format_string = "<i"

# 定义整数数组
numbers = [1, 2, 3, 4, 5]

# 编码整数数组
encoded_data = b"".join(struct.pack(format_string, n) for n in numbers)

# 解码整数数组
decoded_data = [struct.unpack(format_string, encoded_data[i:i+4])[0] for i in range(0, len(encoded_data), 4)]