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

Python3中包装类初始化参数不匹配报错排查与优化

环境类继承改造后的初始化错误问题

问题描述

维护机器学习项目时,新增继承自gym.Env的抽象父类Environment,并修改SushiGoEnv继承该父类后,运行代码触发如下错误:

TypeError: SushiGoEnv.__init__() takes from 1 to 3 positional arguments but 4 were given

错误原因

核心是Python类继承与抽象基类的参数校验冲突,具体拆解:

  1. 改造后的SushiGoEnv的__init__仅接受self、verbose、manual三个参数(后两个带默认值)
  2. selfplay_wrapper中通过继承创建SelfPlayEnv时,由于Environment使用ABCMeta抽象元类,Python会在类创建阶段做严格的参数签名校验。而SelfPlayEnv的__init__调用父类初始化的逻辑,与SushiGoEnv本身的__init__参数签名不兼容,触发了参数数量不匹配的错误
  3. 原代码中SushiGoEnv直接继承gym.Env时无此问题,因为gym.Env未使用抽象元类,不会触发该层级的参数校验

更优的包装类实现方案

推荐使用组合而非继承的方式实现selfplay包装器,这是gym生态中环境包装的标准做法,能彻底避免继承带来的耦合与参数冲突:

优化后的selfplay_wrapper代码

def selfplay_wrapper(env_class):
    class SelfPlayEnv(gym.Wrapper):
        def __init__(self, opponent_type, verbose=False, manual=False):
            # 初始化原始环境实例
            self.base_env = env_class(verbose=verbose, manual=manual)
            super().__init__(self.base_env)
            self.opponent_type = opponent_type
            self.opponent_models = load_all_models(self.base_env)
            self.best_model_name = get_best_model_name(self.base_env.name)

        def reset(self):
            obs = self.base_env.reset()
            self.setup_opponents()

            if self.base_env.current_player_num != self.agent_player_num:   
                self.continue_game()

            return obs

        # 其他方法直接委托给原始环境
        def step(self, action):
            return self.base_env.step(action)

        def render(self, mode='human'):
            return self.base_env.render(mode)

    return SelfPlayEnv

初始化代码(无需修改)

logger.info('\nSetting up the selfplay training environment opponents...')
base_env = get_environment(args.env_name)
env = selfplay_wrapper(base_env)(opponent_type=args.opponent_type, verbose=args.verbose)
env.seed(workerseed)

方案优势

  • 彻底避免继承冲突:通过组合方式包装原始环境,完全避开初始化参数、元类校验等问题
  • 符合gym标准:继承gym.Wrapper可自动获得gym环境的所有默认方法,无需手动实现
  • 解耦性更强:包装器与原始环境耦合度极低,后续修改原始环境参数不会影响包装器

可选临时修复(不推荐长期使用)

若需快速修复,可调整SushiGoEnv的__init__参数,使其与父类兼容:

class SushiGoEnv(Environment):
    metadata = {'render.modes': ['human']}
    def __init__(self, verbose=False, manual=False, n_players=3, device='cuda', turns_taken=0):
        super(SushiGoEnv, self).__init__(n_players=n_players, device=device, turns_taken=turns_taken)
        self.name = 'sushigo'
        self.manual = manual
        self.verbose = verbose

同时修改SelfPlayEnv的初始化调用:

def __init__(self, opponent_type, verbose):
    super(SelfPlayEnv, self).__init__(verbose=verbose)
    # 其他代码不变

但此方式会增加参数冗余,长期来看不如组合方案简洁。


内容的提问来源于stack exchange,提问作者pbuchheit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 14:45:02