如何记录子类的实例化参数

问题描述 投票:0回答:2

我有一个抽象类,我将其子类化。抽象类的特征之一是它有一个属性,用于存储实例化该类时输入的所有参数。例如,以下代码实现了我的目标:

class Parent:
    def __init__(self, parent_parameter):
        pass


class Child(Parent):
    def __init__(self, parent_parameter, child_parameter_1, child_parameter_2):
        self.input_params = locals()
        super(Child, self).__init__(parent_parameter)

使用此代码,我可以通过

self.input_params
属性访问原始输入参数。然而,问题是第一行代码
self.input_params = locals()
必须包含在每个子类中。我想要某种解决方案,例如

class Parent:
    def __init__(self, parent_parameter):
        self.input_params = locals()



class Child(Parent):
    def __init__(self, parent_parameter, child_parameter_1, child_parameter_2):
        super(Child, self).__init__(parent_parameter)

基本上,无论谁编写子类,都不需要注意包含参数日志记录的代码。当然,此块中的代码只会捕获

parent_parameter
参数,不会捕获任何子参数。

子参数当然可以显式传递给父类

__init__
,但这打破了实现者不必担心日志记录的要求,并引入了
*args
**kwargs
,这感觉是多余的。

class Parent:
    def __init__(self, parent_parameter, *args, **kwargs):
        self.input_params = locals()



class Child(Parent):
    def __init__(self, parent_parameter, child_parameter_1, child_parameter_2):
        super(Child, self).__init__(parent_parameter, child_parameter_1, child_parameter_2)

编辑: 也许最好的只是所需代码的文档:

class Parent:
    def __init__(self, parent_parameter):
        # subclass __init__() must begin with `self.input_params = locals()`
        pass


class Child(Parent):
    def __init__(self, parent_parameter, child_parameter_1, child_parameter_2):
        self.input_params = locals()
        super(Child, self).__init__(parent_parameter)
python abstract-class
2个回答
1
投票

好吧,我想,我想出了一些可以通过覆盖

__new__
来起作用的东西。如果这不是Pythonic或hacky,或者这是否是
__new__
的典型用例,我将不胜感激。

class Parent:
    def __new__(cls, *args, **kwargs):
        input_params = {'args': args, 'kwargs': kwargs}
        obj = super(Parent, cls).__new__(cls)
        obj.input_params = input_params
        return obj

    def __init__(self, parent_parameter):
        pass


class Child(Parent):
    def __init__(self, parent_parameter, child_parameter_1, child_parameter_2):
        super(Child, self).__init__(parent_parameter)

0
投票

我看到了你的建议,但我注意到一个问题,如果子类 init 函数有一个未填充的默认参数,它不会在 init_params 中。

我在下面提出一个新版本。我添加了一个包装器,在这个新版本中,如果删除

frame.f_locals["self"] == self
,您可以混合包装器和包装类的初始化参数,这是不可取的。

import inspect


class Parent:
    def __new__(cls, *args, **kwargs):
        input_params = {'args': args, 'kwargs': kwargs}
        obj = super(Parent, cls).__new__(cls)
        obj.v0_input_params = input_params
        return obj

    def __init__(self, parent_arg, parent_kwarg=1):
        # Get the init parameters
        self.init_params = {}
        frame = inspect.stack()[0][0]
        while frame is not None and "self" in frame.f_locals and frame.f_locals["self"] == self:
            self.init_params.update(frame.f_locals)
            frame = frame.f_back
        for ignored in ["self", "frame", "__class__"]:
            self.init_params.pop(ignored)

        # Do your stuff here
        self.parent_arg = parent_arg
        self.parent_kwarg = parent_kwarg


class Child(Parent):
    def __init__(self, parent_arg, child_arg, parent_kwarg=1, child_kwarg=2):
        self.child_arg = child_arg
        self.child_kwarg = child_kwarg
        super().__init__(parent_arg, parent_kwarg=parent_kwarg)


class Wrapper(Parent):
    def __init__(self, parent_arg, child_arg, parent_kwarg=1, child_kwarg=2, wrapper_kwarg=3):
        self.wrapper_kwarg = 3
        self.wrapped_child = Child(parent_arg, child_arg, child_kwarg="replaced")
        super().__init__(parent_arg, parent_kwarg=1)


if __name__ == '__main__':
    agent = Wrapper("set_parent_arg", "set_child_arg")

    print("V0:")
    print("wrapper init params: ", agent.v0_input_params)
    print("wrapper.wrapped_child init params: ", agent.wrapped_child.v0_input_params)
    print()
    print("V1:")
    print("agent init params: ", agent.init_params)
    print("agent.wrapped_child init params: ", agent.wrapped_child.init_params)

这是输出:

V0:
wrapper init params:  {'args': ('set_parent_arg', 'set_child_arg'), 'kwargs': {}}
wrapper.wrapped_child init params:  {'args': ('set_parent_arg', 'set_child_arg'), 'kwargs': {'child_kwarg': 'replaced'}}

V1:
agent init params:  {'parent_arg': 'set_parent_arg', 'parent_kwarg': 1, 'child_arg': 'set_child_arg', 'child_kwarg': 2, 'wrapper_kwarg': 3}
agent.wrapped_child init params:  {'parent_arg': 'set_parent_arg', 'parent_kwarg': 1, 'child_arg': 'set_child_arg', 'child_kwarg': 'replaced'}

Process finished with exit code 0
© www.soinside.com 2019 - 2024. All rights reserved.