2017-08-25 72 views
1

有没有办法阻止一些但不是所有的参数被发送到超类?是否可以选择哪些kwargs传递给Python中的超类?

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

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继承和使用方法,以检查它的关键字

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

+1

'del kwargs ['d']'? –

+0

需要通过'kwargs'来超类那些不在'self.default_properties'.Is this your expectation @CiaranWelsh? – Rajez

+0

我想从'B()。default_properties()'''''''''a'和'b'从B()。default_properties()'传递给'A',而不是'd'。 – CiaranWelsh

回答

3

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

嗯,是的很简单:不要通过它们。你应该知道哪些参数你的类需要和它的哪些参数超(ES)花费太多,所以只能通过超预期的内容:

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} 

,你就别e - check_integrity将使用当前实例的类default_properties,并且您不必关心“正在选择传递给超类的哪些kwargs”。

现在这仍然方式简单化作为输入验证framewoek有效地开展工作,特别是如果你想继承...如果BA适当的子类,它应该能够添加到default_properties,而不必重新定义完全(这是一个明显的干违规)。用户输入验证通常比仅仅检查参数名称涉及更多...您可能想要研究其他库/框架如何解决问题(Django的表单在这里可以想到)。

+0

嗨bruno,非常感谢您的详细解答 - 它对我来说非常宝贵(作为一名自学Python程序员)。我只是有几个问题。首先,当我对你的建议进行修改时,在Base类中调用'self.check_integrity()'会产生一个'NameError'。这是一个[link](http://www.tutorialspoint.com/execute_python_online.php?PID=0Bw_CjBb95KQMbElGSW9IYUdGSHM)来演示错误。其次,是否有必要定义一个空的'default_properties'?这有什么价值?谢谢。 – CiaranWelsh

+0

@CiaranWelsh在我的代码片段中确实存在错误,现在已修复。空的'default_properties'不是_strictly_必需的(并且不需要为空),但是如果没有'check_integrity()',那么会为不带'default_properties'的子类中断。它也使意图更清晰。 –

相关问题