我有以下类层次结构:
class A(object):
def __init__(self, filename, x):
self.x = x
# initialize A from filename
# rest of A's methods
class B(A):
def __init__(self, filename):
super(B, self).__init__(filename, 10)
# rest of B's methods
这两个类都以__init__
方法传递文件名。然后使用文件内容初始化对象中的一些数据。
为了便于测试,我希望能够通过直接传递数据来构造A
或B
实例,而不是从文件中读取对象。我认为使用classmethod
实现的一对工厂函数可能会起作用,但我无法让B
中的版本完全正常工作。这是我到目前为止所做的:
class A(object):
def __init__(self, x):
self.x = x
@classmethod
def construct(cls, filename, x):
a = cls(x)
# initialize a from filename
return a
@classmethod
def test_construct(cls, data, x):
a = cls(x)
# initialize a from data
return a
class B(A):
def __init__(self):
super(B, self).__init__(10)
@classmethod
def construct(cls, filename):
# should construct B from filename
@classmethod
def test_construct(cls, data):
# should construct B from data
答案 0 :(得分:2)
对于B中用于调用超类类方法的类方法,您只需使用super()
,就好像在基类中调用实例一样:
class B(A):
def __init__(self):
super(B, self).__init__(10)
@classmethod
def construct(cls, filename):
# should construct B from filename
return super(B, cls).construct(filename, 10)
修改强>:
正如您在评论中指出的那样,因为您已经在基类构造函数中添加了一个参数,因此存在问题。您应该避免在基类和子类之间对方法签名进行不兼容的更改:B
实例是 A
实例,因此它应该接受您可以对A
实例。
一个选项:
class B(A):
def __init__(self, x=10):
# if you're paranoid insert `assert x==10` here
super(B, self).__init__(x)
@classmethod
def construct(cls, filename):
# should construct B from filename
return super(B, cls).construct(filename, 10)
现在它再次起作用,但你必须相信自己不要将'x'传递给直接构造的B
实例。可能更好的方法是完全从x
中丢失__init__
,看起来你可以通过将其作为类属性或在构造后单独设置它来完成。
答案 1 :(得分:1)
__init__
处的数据。
您可以选择使用filename
并在测试中使用data
:
class A(object):
def __init__(self, x, filename=None, data=None):
if not any((filename, data)):
raise TypeError('either filename or data needs to be provided')
if all((filename, data)):
raise TypeError("both filename and data can't be provided")
self.x = x
if filename:
with open(filename, 'r') as f:
data = f.read() # just an example
编辑:无论如何,如果你想使用特殊的构造函数方法,我就是这样的:
class A(object):
def __init__(self, data, x):
self.x = x
self.data = data
@classmethod
def construct(cls, filename, x):
with open(filename, 'r') as f:
data = f.read()
return cls(data, x)
class B(A):
def __init__(self, data):
super(B, self).__init__(data, 10)
@classmethod
def construct(cls, filename):
with open(filename, 'r') as f:
data = f.read()
# modify data as you wish
return cls(data)
您在计划中致电construct
并在考试中致电__init__
。