工厂功能和子类

时间:2012-01-19 13:16:23

标签: python

我有以下类层次结构:

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__方法传递文件名。然后使用文件内容初始化对象中的一些数据。

为了便于测试,我希望能够通过直接传递数据来构造AB实例,而不是从文件中读取对象。我认为使用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

2 个答案:

答案 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__