结构体¶
假设,我们需要一个数据对象来存储一些球员的信息,可能涉及不同的数据类型,比如姓名,号码,位置等
在 C 语言中,可以创建一个结构体 struct
来存储不同类型的数据
#include <stdio.h>
#include <string.h>
// 定义Player结构体
struct Player {
char name[50]; // 球员姓名
int number; // 球员号码
char position[20]; // 球员位置
};
int main() {
// 创建一个Player实例并初始化
struct Player player1;
strcpy(player1.name, "Micheal Jordan"); // 给name字段赋值
player1.number = 23; // 给number字段赋值
strcpy(player.position, "PG"); // 给position字段赋值
// 打印Player实例的信息
printf("Name: %s\n", player1.name);
printf("Number: %d\n", player1.number);
printf("Position: %s\n", player1.position);
return 0;
}
在 Python 中,并没有内置的结构体类型,但可以使用 tuple
, dict
, namedtuple
, class
, dataclass
等来实现
虽然 Python 中有一个内置的
struct
模块,但主要用于处理二进制数据,与 C 的结构体完全不是一个概念
使用基础类型实现¶
缺少信息或信息类型错误等依然可以创建
- tuple
jordan = ('Micheal Jordan', 23, 'PG')
jordan[2] # 取值基于索引,很不直观
- dict
jordan = {'name': 'Micheal Jordan', 'number': 23, 'position': 'PG'}
jordan['position'] # 无法像获取属性一样 jordan.position 取值
Named Tuple 实现¶
数据无法修改,无法比较
collections.namedtuple
没有默认值,且不能继承
from collections import namedtuple
Player = namedtuple('Player', ['name', 'number', 'position'])
jordan = Player('Micheal Jordan', 23, 'PG')
bryant = Player('Kobe Bryant', 24) # 数据不匹配会报错
jordan.position # 可以使用 . 语法获取属性
typing.NamedTuple
支持默认值和方法,更加灵活
from typing import NamedTuple
class Player(NamedTuple):
name: str # 可以加类型注解
number: int = 0 # 可以定义默认值
position: str
player_instance = Player("Lionel Messi", 10, "Forward")
自定义类实现¶
class Player:
def __init__(self, name, number, position):
self.name = name
self.number = number
self.position = position
jordan = Player('Micheal Jordan', 23, 'PG') # 使用位置参数创建对象
bryant = Player(name='Kobe Bryant', number=24, position='PG') # 使用键值参数创建对象
jordan.position # 获取属性
bryant.position = 'SF' # 修改属性
"""
不足之处
bryant # 对象描述不友好:<__main__.Player at 0x33426a512b7>,需要实现 __repr__ 方法来自定义描述
bryant < jordan # 无法比较:TypeError,需要实现 __eq__, __gt__, __ge__ 等方法来实现比较
"""
# 完善代码
class Player:
def __init__(self, name, number, position):
pass
def __repr__(self):
return f'Player: \n {self.name}\t #{self.number}\t @{self.position}'
def __eq__(self, other):
return self.number == other.number
def __gt__(self, other):
return self.number > other.number
def __ge__(self, other):
return self.number >= other.number
dataclass¶
@dataclass
相当于语法糖,简化或者说自动实现了 __init__
, __repr__
, __eq__
, ... 等方法
另外数据类除了能存储数据,还可以包含方法,提供更多面向对象的特性
如果要使数据类声明后不可变,可使用 @dataclass(frozen=True)
from dataclasses import dataclass
from typing import List, Any
@dataclass
class Player:
name: str # 类型注释虽然不是必须的,但强烈建议使用,如果不想限制类型可以使用Any
number: int = 0 # 可以传默认值,但默认值不能使用可变类型(mutable)
position: str
bryant = Player('Kobe Bryant', 24, 'PG')
james = Player('Lebron James', 23, 'SF')
james # 描述友好,因为自动实现了__init__方法:Player(name='Lebron James', number=23, position='SF')
@dataclass
class Team:
name: str
players: List[Player] # 数据嵌套
Lakers = Team('Los Angeles Lakers', [bryant, james])
Lakers # Team(name='Los Angeles Lakers', players=[Player(name='Kobe Bryant', number=24, position='PG'), Player(name='Lebron James', number=23, position='SF')])