是否有可能选择将哪些kwargs传递给python中的超类?

时间:2017-08-25 10:13:09

标签: python class inheritance subclass superclass

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

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

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为什么不更新为{{ 1}}在上面的例子中)

尝试从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'] 被传递给超类,即使它只在子类中需要。但是,da参数在b中使用,应从A传递到B

1 个答案:

答案 0 :(得分:3)

  

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

嗯,很简单:不要传递它们。你应该知道你的类所采用的参数以及它的超类所依赖的参数,所以只传递超类期望的参数:

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,你不必关心“选择你传递给超类的哪些kwargs”。

现在仍然可以通过简化来有效地作为输入验证框架,特别是如果你想要继承...如果BA的正确子类,它应该能够添加到default_properties而不必完全重新定义它(这是明显的DRY违规)。用户输入验证通常比仅检查参数名称更复杂......您可能想要研究其他库/框架如何解决问题(这里会想到Django的形式)。