10

The problem is quite simple. If a class B inherit a class A and wants to override a ´classmethod´ that is used as a constructor (I guess you call that a "factory method"). The problem is that B.classmethod will want to reuse A.classmethod, but then it will have to create an instance of the class A, while it subclasses the class A - since, as a classmethod, it has no self. And then, it doesn't seem the right way to design that.

I did the example trivial, I do more complicate stuff by reading numpy arrays, etc. But I guess there is no loss of information here.

class A:
    def __init__(self, a):
        self.el1 = a

    @classmethod
    def from_csv(cls, csv_file):
        a = read_csv(csv_file) 
        return cls(a)

    @classmethod
    def from_hdf5 ...

class B(A):
    def __init__(self, a, b)
        A.(self, a)
        self.el2 = b

    @classmethod
    def from_csv(cls, csv_file):
        A_ = A.from_csv(csv_file) #instance of A created in B(A)
        b = [a_*2 for a_ in A.el]
        return cls(A.el, b) 

Is there a pythonic way to deal with that?

1
  • 2
    I have the same problem, and it's surprising that this question doesn't have a satisfying answer. It should! Commented Feb 27, 2020 at 14:04

2 Answers 2

2

After doing some different trials. My conclusion is that you should override a classmethod without reusing the code inside. So the best way I found, for my particular problem, is to make the classmethod as simply as possible and put the code I want to reuse in another method, static in my case, since the classmethod is a constructor.

Sign up to request clarification or add additional context in comments.

Comments

1

One easy solution would be to have class B's __init__ method have a default value for its b parameter. This would let the cls(a) call made by A.from_csv work when it is inherited. If the default is used, the __init__ method could calculate a value to store from a (as you do in B.from_csv now).

class B(A):
    def __init__(self, a, b=None):
        super().__init__(a)   # use super(B, self).__init__(a) if you're in Python 2
        self.el2 = b if b is not None else [i*2 for i in a]

    # don't override from_csv, B.from_csv will already return a B instance!

3 Comments

This solution doesn't seem well done for my problem, since, as suggested in the example, I have plenty of factory method, I don't get how to deal with that with your solution. Currently, if I get it well, I'm adopting a close solution. A.from_csv() calls a @staticmethod format_array() that is overloaded.
@Touki: I guess it depends on how your B instances should be constructed in the other factories. If the b parameter should always be derived from the a parameter (e.g. by doubling each value, as in your example), then I think the idea of doing that derivation in the __init__ method will carry over (you don't need to override the A factories, which will construct B instances when they're called with cls equal to B). If the b values need to come from somewhere else, there's not any easy way to inherit, I don't think (unless you factor out more bits of the code).
In the second case, isn't it better to abandon @classmethod and to replace it whether (1) by parsing an enormous amount of args in init to let him play the role of multiple constructor or (2) by simply have an empty constructor, and then by calling a method?A.(), A.from_csv()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.