You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python新手求助:如何将足球赛事JSON转为自定义对象结构?

解决思路:从JSON到Python对象的完整流程

嘿,作为Python OOP新手,你碰到的这个场景太常见了——把结构化的足球赛事JSON转换成有明确关联的自定义对象,这样后续的统计计算、数据累积和数据库存储都会清晰很多。我来一步步帮你拆解,从类的定义到JSON解析,再到对象关联,最后聊聊累积统计和数据库的实现思路。

第一步:先定义对应业务的Python类

首先,我们要把JSON里的每个实体(球员、点球、进球、球队、赛事)都转换成Python类,这样每个对象的属性和关联关系都能清晰定义。这里要重点处理对象间的关联(比如点球属于哪个球员,进球的射手和助攻是谁):

class Player:
    def __init__(self, nr, surname, name, role):
        self.nr = nr  # 球衣号
        self.surname = surname
        self.name = name
        self.role = role
        self.is_starting = False  # 是否首发,后续标记
        self.penalties = []  # 该球员的所有点球
        self.goals = []  # 该球员的所有进球
        self.assists = []  # 该球员的所有助攻

class Penalty:
    def __init__(self, time, nr):
        self.time = time  # 点球时间
        self.player_nr = nr  # 罚球球员号码
        self.player = None  # 后续关联到Player对象

class Goal:
    def __init__(self, time, scorer_nr, assist_nrs=None, shot_on_goal="N"):
        self.time = time
        self.scorer_nr = scorer_nr  # 射手号码
        self.assist_nrs = assist_nrs or []  # 助攻球员号码列表
        self.shot_on_goal = shot_on_goal
        self.scorer = None  # 关联射手Player对象
        self.assisters = []  # 关联助攻Player对象列表

class Team:
    def __init__(self, name):
        self.name = name
        self.players = {}  # 用球衣号做键:{nr: Player对象},方便快速查找
        self.starting_lineup = []  # 首发Player对象列表
        self.penalties = []  # 球队所有点球
        self.goals = []  # 球队所有进球
        # 统计字段,后续自动计算
        self.total_goals = 0
        self.total_penalties = 0

class Game:
    def __init__(self, time, spectators, location, referees=None):
        self.time = time  # 比赛日期
        self.spectators = spectators  # 观众人数
        self.location = location  # 比赛场地
        self.referees = referees or []  # 裁判列表
        self.main_referee = None  # 主裁判
        self.teams = []  # 两支参赛Team对象

第二步:解析JSON,映射对象并建立关联

接下来写一个解析函数,把JSON数据逐个转换成上面的类实例,同时手动建立对象间的关联(比如把点球绑定到对应的球员)。这里要注意JSON里的字段可能是单个字典或列表(比如Penalty可能是一个或多个),需要做类型判断:

def parse_team(team_data):
    """解析单支球队的JSON数据,返回Team对象"""
    team = Team(team_data["TeamName"])
    
    # 1. 先创建所有球员,存入球队的players字典
    for player_data in team_data["Players"]["Player"]:
        player = Player(
            nr=player_data["Nr"],
            surname=player_data["Surname"],
            name=player_data["Name"],
            role=player_data["Role"]
        )
        team.players[player.nr] = player
    
    # 2. 标记首发球员
    for starter_data in team_data["StartingLineUp"]["Player"]:
        nr = starter_data["Nr"]
        if nr in team.players:
            team.players[nr].is_starting = True
            team.starting_lineup.append(team.players[nr])
    
    # 3. 解析点球,关联到对应球员
    if "Penalties" in team_data:
        penalty_raw = team_data["Penalties"]["Penalty"]
        # 处理单个点球(字典)或多个点球(列表)
        penalties = penalty_raw if isinstance(penalty_raw, list) else [penalty_raw]
        for p_data in penalties:
            penalty = Penalty(time=p_data["Time"], nr=p_data["Nr"])
            team.penalties.append(penalty)
            team.total_penalties += 1
            # 关联到球员
            if penalty.player_nr in team.players:
                penalty.player = team.players[penalty.player_nr]
                penalty.player.penalties.append(penalty)
    
    # 4. 解析进球,关联射手和助攻球员
    if "Goals" in team_data:
        goal_raw = team_data["Goals"]["VG"]
        goals = goal_raw if isinstance(goal_raw, list) else [goal_raw]
        for g_data in goals:
            # 处理助攻球员(可能是单个字典或列表)
            assist_nrs = []
            if "P" in g_data:
                p_data = g_data["P"]
                if isinstance(p_data, list):
                    assist_nrs = [item["Nr"] for item in p_data]
                else:
                    assist_nrs = [p_data["Nr"]]
            goal = Goal(
                time=g_data["Time"],
                scorer_nr=g_data["Nr"],
                assist_nrs=assist_nrs,
                shot_on_goal=g_data.get("ShotOnGoal", "N")
            )
            team.goals.append(goal)
            team.total_goals += 1
            # 关联射手
            if goal.scorer_nr in team.players:
                goal.scorer = team.players[goal.scorer_nr]
                goal.scorer.goals.append(goal)
            # 关联助攻球员
            for nr in goal.assist_nrs:
                if nr in team.players:
                    assister = team.players[nr]
                    goal.assisters.append(assister)
                    assister.assists.append(goal)
    
    # 球员替换(PlayerChanges)可以按需扩展,比如记录替换时间和球员
    return team

def parse_game(json_data):
    """解析整个赛事的JSON数据,返回Game对象"""
    game_raw = json_data["Game"]
    
    # 处理裁判和主裁判
    referees = [f"{ref['Name']} {ref['Surname']}" for ref in game_raw.get("T", [])]
    main_referee = f"{game_raw['VT']['Name']} {game_raw['VT']['Surname']}" if "VT" in game_raw else None
    
    game = Game(
        time=game_raw["Time"],
        spectators=game_raw["Spectators"],
        location=game_raw["Location"],
        referees=referees
    )
    game.main_referee = main_referee
    
    # 解析两支球队
    for team_data in game_raw["Team"]:
        team = parse_team(team_data)
        game.teams.append(team)
    
    return game

第三步:累积统计与数据库存储

现在你可以轻松处理多场赛事的累积统计了,比如维护一个全局字典记录每个球员的生涯数据,然后把赛事和球员数据存入MySQL:

累积统计示例

# 全局字典,用(名字,姓氏)作为唯一键(你说姓名组合唯一)
all_player_cumulative = {}

def update_cumulative_stats(game):
    """更新球员的累积统计数据"""
    for team in game.teams:
        for player in team.players.values():
            key = (player.name, player.surname)
            if key not in all_player_cumulative:
                # 初始化新球员的累积数据
                all_player_cumulative[key] = {
                    "total_goals": 0,
                    "total_penalties": 0,
                    "total_assists": 0,
                    "games_played": 0,
                    "starts": 0
                }
            # 更新统计值
            stats = all_player_cumulative[key]
            stats["total_goals"] += len(player.goals)
            stats["total_penalties"] += len(player.penalties)
            stats["total_assists"] += len(player.assists)
            stats["games_played"] += 1
            if player.is_starting:
                stats["starts"] += 1

MySQL存储示例

先确保安装了mysql-connector-python(pip install mysql-connector-python),然后写存储函数:

import mysql.connector

def save_game_to_db(game, cumulative_stats):
    """把赛事数据和累积统计存入MySQL"""
    # 连接数据库(替换成你的配置)
    conn = mysql.connector.connect(
        host="localhost",
        user="your_username",
        password="your_password",
        database="football_db"
    )
    cursor = conn.cursor()
    
    # 1. 插入赛事记录
    insert_game_sql = """
    INSERT INTO games (match_time, spectators, location, main_referee)
    VALUES (%s, %s, %s, %s)
    """
    cursor.execute(insert_game_sql, (game.time, game.spectators, game.location, game.main_referee))
    game_id = cursor.lastrowid  # 获取刚插入的赛事ID,用于关联球队
    
    # 2. 插入球队记录
    for team in game.teams:
        insert_team_sql = """
        INSERT INTO teams (game_id, team_name, total_goals, total_penalties)
        VALUES (%s, %s, %s, %s)
        """
        cursor.execute(insert_team_sql, (game_id, team.name, team.total_goals, team.total_penalties))
        team_id = cursor.lastrowid  # 获取球队ID,用于关联球员
        
        # 3. 插入球员记录(包含累积统计)
        for player in team.players.values():
            key = (player.name, player.surname)
            stats = cumulative_stats[key]
            insert_player_sql = """
            INSERT INTO players (team_id, jersey_nr, first_name, last_name, role, is_starting,
                                total_goals, total_penalties, total_assists, games_played, starts)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
            """
            cursor.execute(insert_player_sql, (
                team_id, player.nr, player.name, player.surname, player.role, player.is_starting,
                stats["total_goals"], stats["total_penalties"], stats["total_assists"],
                stats["games_played"], stats["starts"]
            ))
    
    # 提交事务并关闭连接
    conn.commit()
    cursor.close()
    conn.close()

第四步:完整使用流程

import json

# 读取单场赛事JSON文件
with open("match1.json", "r", encoding="utf-8") as f:
    match_json = json.load(f)

# 解析成Game对象
game = parse_game(match_json)

# 更新累积统计
update_cumulative_stats(game)

# 存入数据库
save_game_to_db(game, all_player_cumulative)

# 重复以上步骤处理其他JSON文件即可

为什么不用字典?

你担心字典无法处理关联是对的——字典是扁平的键值对,每次查找球员或关联点球都要手动遍历,代码会越来越乱。而自定义对象可以把数据和行为封装在一起,比如你可以给Player类加一个方法:

def get_total_contributions(self):
    """计算球员的总贡献:进球+助攻+点球"""
    return len(self.goals) + len(self.assists) + len(self.penalties)

这样后续统计会非常方便,扩展性也强。

关于marshmallow

marshmallow是用来简化序列化/反序列化的,但对于OOP新手来说,手动解析能让你更清晰地理解对象之间的关联逻辑。等你熟悉了类和对象的关系后,再去尝试marshmallow会更容易上手——它本质上是帮你自动完成“JSON转对象”的映射,不用手动写解析函数。


内容的提问来源于stack exchange,提问作者Oskars Sjomkāns

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:23:27