1 python inheritance keyword-argument python-3.x
考虑以下示例代码:
#!/usr/bin/python3
class Parent:
def __init__(self, **kwargs):
# Expect data1, data2
self.values = kwargs
# Accessor method to set object values
def setvalue(self, k, v):
self.values[k] = v
# Accessor method to get/return object values
def getvalue(self, k):
return self.vlaues.get(k, None)
class Child(Parent):
def __init__(self, **kwargs):
# Expect data3, data4
self.values = kwargs
# Accessor method to set object values
def setvalue(self, k, v):
self.values[k] = v
# Accessor method to get/return object values
def getvalue(self, k):
return self.values.get(k, None)
def main():
new_object = Child(data1 = 'abc', data2 = 'def',
data3 = 'ghi', data4 = 'jkl')
for v in new_object.values:
print('{}: {}'.format(v, new_object.getvalue(v)))
new_object.setvalue('data1', 'tuv')
new_object.setvalue('data4', 'xyz')
for v in new_object.values:
print('{}: {}'.format(v, new_object.getvalue(v)))
if __name__ == "__main__": main()
Run Code Online (Sandbox Code Playgroud)
我想知道如何kwargs在仍然使用一些基本继承的同时利用灵活性。在我正在编写的实际应用程序中,每个类实际上都有许多与之相关的不同属性。
我担心的是,因为kwargs是非常灵活(并且模糊不清),我不能保持我的课的亲子关系- ,data1,data2,data3并且data4将全部得到应用到Child类。
我如何确保data1和data2是Parent超类的属性,以及data3和data4是Child子类的属性?
我正在尝试以“正确的方式”设计我的类结构,同时保持代码的简单和优雅。它甚至重要吗?也许我在这方面走错了路。有一个更好的方法吗?
对不起,如果我在这里闲逛。只是试图理解。预先感谢您的帮助和耐心...
您的第一个问题是您实际上并没有首先创建属性。如果需要属性,请创建属性。如果需要键值映射,请创建映射。您创建的是具有非标准 API 的特殊用途、功能有限的映射。没有充分的理由这样做。
如果你想确保某物是某物的一个属性,它首先必须是一个属性,你通常用self.spam = eggs赋值来做(尽管在某些情况下你用setattr或 甚至来做self.__dict__.update)。
如何确保 data1 和 data2 是 Parent 超类的属性,而 data3 和 data4 是 Child 子类的属性?
如果确保它是类的不变量的一部分,您希望在每个类中明确地确保它,并将任何剩余的参数与super. 例如:
class Parent:
def __init__(self, **kwargs):
self.data1 = kwargs.pop('data1', None)
self.data2 = kwargs.pop('data2', None)
super().__init__(**kwargs)
class Child(Parent):
def __init__(self, **kwargs):
self.data3 = kwargs.pop('data3', None)
self.data4 = kwargs.pop('data4', None)
super().__init__(**kwargs)
Run Code Online (Sandbox Code Playgroud)
但是您可能会注意到,您并没有真正从这里的额外通用性中获得任何好处;你可以——而且可能应该——像这样写同样的东西:
class Parent:
def __init__(self, *, data1=None, data2=None, **kwargs):
super().__init__(**kwargs)
self.data1 = data1
self.data2 = data2
class Child(Parent):
def __init__(self, *, data3=None, data4=None, **kwargs):
super().__init__(**kwargs)
self.data3 = data3
self.data4 = data4
Run Code Online (Sandbox Code Playgroud)
话虽如此,我认为您首先是出于误解进行操作:
我担心的是,由于 kwargs 非常灵活(而且模糊不清),我无法维护我的类的父子关系——data1、data2、data3 和 data4 都将应用于 Child 类。
不,这些属性都没有应用于任一类。它们被应用于每个实例Child——但毫无疑问,它们是作为Parent实例还是作为Child实例获得这些属性;他们只是通过成为带有 a 的对象__dict__并进行self.spam = eggs分配来获得它们。无论您将实例视为 aParent还是 a Child,这些属性都在那里——以及您在构造后很长时间添加的随机额外属性,或从 继承的标准属性object,或其他任何东西。
如果你真的,真的想强制那些Parent不是Child只有dataand 的实例data2,你可以用__slots__, @property,显式描述符来做到这一点......让我们做第一个,因为它在这里最简单和最清晰:
class Parent:
__slots__ = ('data1', 'data2')
def __init__(self, **kwargs):
self.data1 = kwargs.pop('data1', None)
self.data2 = kwargs.pop('data2', None)
super().__init__(**kwargs)
class Child(Parent):
__slots__ = ('data3', 'data4')
def __init__(self, **kwargs):
self.data3 = kwargs.pop('data3', None)
self.data4 = kwargs.pop('data4', None)
super().__init__(**kwargs)
Run Code Online (Sandbox Code Playgroud)
现在,任何data3在Parent实例上分配属性的尝试都会引发AttributeError,除非它实际上是某个添加data3插槽的子类的实例,例如Child.
| 归档时间: |
|
| 查看次数: |
1278 次 |
| 最近记录: |