在python中,是否可以有选择地将哪些kwarg传递给超类?

2024-05-13 09:28:29 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有办法阻止某些但不是所有的参数被发送到超类?你知道吗

我有一个验证用户输入的基类:

class Base(object):
    def __init__(self, **kwargs):
        self.kwargs = kwargs
        super(Base, self).__init__()

    @staticmethod
    def check_integrity(allowed, given):
        """
        Verify user input.
        :param allowed: list. Keys allowed in class
        :param given: list. Keys given by user
        :return:
        """
        for key in given:
            if key not in allowed:
                raise Exception('{} not in {}'.format(key, allowed))

>>> base = Base()
>>> print base.__dict__
output[0]: {'kwargs': {}}

A继承自Base,并使用该方法检查其关键字

class A(Base):
    def __init__(self, **kwargs):
        super(A, self).__init__(**kwargs)
        self.default_properties = {'a': 1,
                                   'b': 2}

        self.check_integrity(self.default_properties.keys(), kwargs.keys())

>>> a = A(a=4)
>>> print a.__dict__
output[1]: {'default_properties': {'a': 1, 'b': 2}, 'kwargs': {'a': 4}}

我还应该提到,我在这个类中使用了另一个方法来更新类属性,因为这是一个与问题无关的复杂问题(因此在上面的示例中,为什么a没有更新为4

当尝试从A继承并向子类添加额外的kwargs时,会出现问题:

class B(A):
    def __init__(self, **kwargs):
        super(B, self).__init__(**kwargs)

        self.default_properties = {'a': 2,
                                   'c': 3,
                                   'd': 4}

        self.check_integrity(self.default_properties.keys(), kwargs.keys())



>>> b = B(d=5)


Traceback (most recent call last):
  File "/home/b3053674/Documents/PyCoTools/PyCoTools/Tests/scrap_paper.py", line 112, in <module>
    b = B(d=5)
  File "/home/b3053674/Documents/PyCoTools/PyCoTools/Tests/scrap_paper.py", line 96, in __init__
    super(B, self).__init__(**kwargs)
  File "/home/b3053674/Documents/PyCoTools/PyCoTools/Tests/scrap_paper.py", line 92, in __init__
    self.check_integrity(self.default_properties.keys(), kwargs.keys())
  File "/home/b3053674/Documents/PyCoTools/PyCoTools/Tests/scrap_paper.py", line 84, in check_integrity
    raise Exception('{} not in {}'.format(key, allowed))
Exception: d not in ['a', 'b']

这里d被传递给超类,即使它只在子类中是必需的。但是,ab参数用于A,应该从B传递到A。你知道吗


Tags: inselfdefaultbaseinitdefcheckproperties
1条回答
网友
1楼 · 发布于 2024-05-13 09:28:29

Is there a way to prevent some but not all arguments from being sent up to a superclass?

是的,很简单:不要通过。你应该知道你的类接受哪些参数,以及它的超类也接受哪些参数,所以只传递超类所期望的:

class Base(object):
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

class Child(object):
    def __init__(self, arg1, arg2, arg3):
        super(Child, self).__init__(arg1, arg2)
        self.arg3 = arg3

以上内容简单易读,易于维护,并保证正常工作。如果你想要默认值也不是问题:

class Base(object):
    def __init__(self, arg1=1, arg2=2):
        self.arg1 = arg1
        self.arg2 = arg2

class Child(object):
    def __init__(self, arg1=1, arg2=2, arg3=3):
        super(Child, self).__init__(arg1, arg2)
        self.arg3 = arg3

现在,如果类的职责是根据给定的“模式”(代码段中的default_properties)验证任意用户输入,那么代码中确实存在两个逻辑错误—主要是1。验证初始值设定项和2中的输入。在重写对象的default_properties之前调用父类的初始值设定项,因此当调用超类初始值设定项时,它不会根据正确的模式进行验证。另外,您正在将default_properties定义为初始值设定项中的实例属性,因此,如果您只是交换指令,先定义default_propertie,然后才调用父级的初始值设定项,那么这个将重新定义default_properties

一个简单的解决方法是将default_properties设为类属性:

class Base(object):

    # empty by default
    default_properties = {}

    def __init__(self, **kwargs):                
        self.kwargs = kwargs
        # object.__init__ is a noop so no need for a super call here
        self.check_integrity()                

    def check_integrity(self):
        """
        Verify user input.
        """
        for key in self.kwargs:
            if key not in self.default_properties:
                raise ValueError('{} not allowed in {}'.format(key, self.default_properties))

然后你就不必重写初始值设定项了:

class A(Base):
    default_properties = {'a': 1,
                          'b': 2}


class B(A):
    default_properties = {'a': 1,
                          'b': 2,
                          'd': 3}

完成了-check_integrity将使用当前实例的类default_properties,您不必关心“对传递给超类的kwarg进行选择”。你知道吗

现在这仍然是一种简单化的方法,可以有效地作为输入验证framewoek工作,特别是如果您想要继承的话。。。如果BA的适当子类,那么它应该能够添加到default_properties,而不必完全重新定义它(这是一个明显的干冲突)。用户输入验证通常比检查参数名要复杂得多。。。您可能想研究其他libs/框架是如何解决这个问题的(这里想到的是Django的表单)。你知道吗

相关问题 更多 >