有没有办法阻止某些但不是所有的参数被发送到超类?
我有一个验证用户输入的基类:
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']
被传递给超类,即使它只在子类中需要。但是,d
和a
参数在b
中使用,应从A
传递到B
。
答案 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”。
现在仍然可以通过简化来有效地作为输入验证框架,特别是如果你想要继承...如果B
是A
的正确子类,它应该能够添加到default_properties
而不必完全重新定义它(这是明显的DRY违规)。用户输入验证通常比仅检查参数名称更复杂......您可能想要研究其他库/框架如何解决问题(这里会想到Django的形式)。