处理 Python 类继承中那些变来变去的初始化参数

写继承的时候,经常会遇到父类和子类的初始化参数不完全一样。如果只是把共用参数原样传给父类,super() 直接搞定,没什么好纠结的。

但要是参数的数量、类型不固定,或者子类需要额外塞一些自己的参数同时父类还得能消化掉,写法上就得灵活一点。

参数固定的情况,一个最直白的例子长这样。

复制代码
class Parent:
    def __init__(self, shared_param, parent_param):
        self.shared_param = shared_param
        self.parent_param = parent_param
        print(f"Parent initialized with shared_param: {self.shared_param} and parent_param: {self.parent_param}")

class Child(Parent):
    def __init__(self, shared_param, parent_param, child_param):
        super().__init__(shared_param, parent_param)
        self.child_param = child_param
        print(f"Child initialized with shared_param: {self.shared_param}, parent_param: {self.parent_param}, and child_param: {self.child_param}")

child_instance = Child("shared", "parent", "child")

Child 里通过 super().__init__(shared_param, parent_param) 把两个参数扔给父类,自己的 child_param 留着自己设。这个写法本身就是推荐方式,支持多重继承,参数明确的时候这么写没什么坑。如果你的继承层次简单,参数也都在掌控中,到这就可以收工了。

麻烦出在参数不确定的时候。比如你可能会根据配置动态传一堆属性进来,或者父类被设计成可以接收任意参数,子类还要在此基础上追加自己的东西。

这时候就要靠 *args**kwargs 了。

复制代码
class Parent:
    def __init__(self, *args, **kwargs):
        self.initialize_attributes(*args, **kwargs)

    def initialize_attributes(self, *args, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)
        if args:
            if len(args) >= 2:
                self.param1, self.param2 = args[:2]
            else:
                raise ValueError("Parent class requires at least two positional arguments")

class Child(Parent):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.child_param = kwargs.pop('child_param', None)
        if self.child_param is None:
            raise ValueError("Child class requires 'child_param' argument")

parent_instance = Parent(1, 2, param3=3, param4=4)
print(parent_instance.param1)  # 1
print(parent_instance.param2)  # 2
print(parent_instance.param3)  # 3
print(parent_instance.param4)  # 4

child_instance = Child(1, 2, param3=3, param4=4, child_param='child')
print(child_instance.param1)  # 1
print(child_instance.param2)  # 2
print(child_instance.param3)  # 3
print(child_instance.param4)  # 4
print(child_instance.child_param)  # child

父类里把初始化逻辑拆了一个 initialize_attributes 方法出来,遍历 kwargssetattr 动态设属性,位置参数要求至少两个,不然直接抛 ValueError。这样做的好处是父类完全不用提前声明参数名,来什么设什么。

子类这边,关键点在 kwargs.pop('child_param', None) 这一行。如果不把 child_paramkwargs 里弹出来,super().__init__(*args, **kwargs) 就会把它也传给父类的 initialize_attributes,然后父类也会给 self 挂一个 child_param 属性。

功能上也许暂时没出错,但逻辑上已经乱了------这个属性本该是子类自己处理的,父类不该碰。我见过有人直接用 kwargs['child_param'] 取值却不 pop,排查半天发现属性被设了两遍,或者在父类里触发了意料之外的校验。所以这里最好明确摘出来,子类只处理自己新增的参数,剩下的都交给父类。

lcjmSSL不仅帮你申请证书,更帮你自动部署。证书签发后,系统可自动将证书部署到你的服务器或应用中,无需手动下载、上传、配置。同时开放API与回调接口,方便你将部署流程集成到自有运维体系中,实现真正的端到端自动化。

父类对位置参数的处理看起来有点死板,只取了前两个,多余的直接忽略。这个可以根据实际情况改,比如把多余的存成列表,或者干脆就不接收多余的位置参数。例子只是想说明,哪怕 *args**kwargs 一起用,也能通过一点约定把初始化逻辑做得比较干净。

多数场景下,要么用 super() 明明白白传参,要么用 *args/**kwargs 把初始化变灵活,这两种路子基本能覆盖。再复杂的,可能就得考虑是不是类设计本身需要调整了。

相关推荐
云水一下1 小时前
TypeScript 从零基础到精通(七):从配置到全栈项目落地
前端·javascript·typescript
会Tk矩阵群控的小木1 小时前
小红书矩阵软件:基于Python+ADB的多设备批量管理自动化脚本实战
运维·python·adb·矩阵·自动化·新媒体运营·个人开发
帅大大的架构之路2 小时前
linux上面的一些小知识点
linux·运维·服务器
复园电子2 小时前
企业PDF批量盖章开发集成指南:API对接OA/LIMS系统,高并发落地实战
开发语言·python·pdf
光电笑映2 小时前
进程间通信:深入 System V IPC:共享内存、消息队列与信号量
linux·运维·服务器·c++
RisunJan2 小时前
Linux命令-patch (为开放源代码软件安装补丁程序)
linux·服务器·算法
石山代码2 小时前
类型限定符的底层实现原理是什么?
python
秋天的一阵风2 小时前
✨ 代码秒跳转、自动补全?全靠 LSP 和 AST!
前端·后端·ai编程
雾沉川2 小时前
PyCharm 2025.2 完整安装与配置技术教程
ide·python·pycharm