9

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?

Touki
  • 833
  • 2
  • 9
  • 20

2 Answers2

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.

Touki
  • 833
  • 2
  • 9
  • 20
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!
Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • 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 Jan 04 '14 at 20:10
  • @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). – Blckknght Jan 05 '14 at 04:25
  • 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() – Touki Jan 05 '14 at 11:18