1

I would like to implement the following structure:

class Case(nx.Graph):   
    def __init__(self, case):       
        if case == 1:
            self = Case1()
        if case == 2:
            self = Case2()    

class Case1(Case):
    def __init__(self):
        super(Case1, self).__init__()
        print "Case1"

class Case2(Case):
    def __init__(self):
        super(Case2, self).__init__() 
        print "Case2"

For instance, if I create the following object:

graph = Case(1)

a new Object of the class Case1 should be created. In the __init__ of the class Case1 the super() fuction should call the __init__ function of the networkx.Graph().

If I run that code, the result should be a networkx.Graph object called "graph" and it should print Case1.

4
  • 1
    This pattern is called a class factory, example in PY3: python-3-patterns-idioms-test.readthedocs.org/en/latest/… Commented Mar 11, 2016 at 19:34
  • No, you do not want this. Classes shouldn't magically change themselves into other classes, and parent classes shouldn't be aware of their children. If you write case = Case(x), you expect to get an instance of Case, not any other class. Have plain Case1 and Case2 classes, even if they inherit from a common parent, and leave the decision which class to construct outside any of those classes. Commented Mar 11, 2016 at 19:35
  • another good link: informit.com/articles/article.aspx?p=2131418 Commented Mar 11, 2016 at 19:42
  • @deceze It's not entirely frowned upon. Python's class instantiation implicitly supports this, as Class.__init__ is only called on a new object if Class.__new__ actually returns an instance of Class. Commented Mar 11, 2016 at 20:12

3 Answers 3

1

When you say self = ..., you are just redefining self. You aren't changing it. To do what you want, use __new__ instead:

class Case(nx.Graph):
    def __new__(self, case):
        if case == 1:
            return Case1()
        elif case == 2:
            return Case2()
        else:
            raise ValueError("Invalid argument")

You really shouldn't do this, though. If you want a different instance for a different case, do it when you create the instance, but a class should not depend on its children in order to work.

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

3 Comments

and now it's getting buggy because Case1 inherits from Case and thus also has this __new__-method.
Thank you for your answer! What you mean by "do it wehen you create the instance" --> would help me a lot if you could give me an example with that code.
@lars111: I mean, say x = Case1(), not x = Case(1). It gets buggy when you try to do it this way. For one thing, since Case1 and Case2 inherit from Case, you would still need to do x = Case1(1) because __new__ needs that argument. It just gets really buggy when you make a parent class depend on its children.
0

One way of doing it is by not invoking __init__ for the subclasses but putting these in a seperate method, i.e. setup and rewriting the __class__ attribute:

class Case(object):   
    def __init__(self, case):
        # Maybe even call the init of the superclass:
        super(Case, self).__init__()
        # Do the setup that is common to all Cases:
        self.setup()
        # Change the class of the instance depending on your case:
        if case == 1:
            self.__class__ = Case1  # No () here!
        elif case == 2:
            self.__class__ = Case2
        else:
            raise ValueError()
        # Call the setup of the subclass
        self.setup()

    def setup(self):
        print('Setup of Case called.')


class Case1(Case):

    def setup(self):
        print('Setup of Case1 called.')

class Case2(Case):

    def setup(self):
        print('Setup of Case2 called.')

when I try to create a Case1:

a = Case(1)

it prints:

Setup of Case called.
Setup of Case1 called.

But there might even be proper (builtin-modules, packages) recipes for doing something like this.

Comments

0

This is a classic Factory pattern. I would implement it using a static method as follows:

class Case(object):   

    @staticmethod
    def factory(case):
        if case == 1:
            return Case1()
        if case == 2:
            return Case2()
        raise NotImplementedError('Unknown case: %r'%case)

class Case1(Case):
    def __init__(self):
        super(Case1, self).__init__()
        print "Case1"

class Case2(Case):
    def __init__(self):
        super(Case2, self).__init__() 
        print "Case2"

You can extend as appropriate for args to pass to the initializer. IN usage, you might see something like the following:

c1 = Case.factory(1)
c2 = Case.factory(2)
print type(c1), type(c2)
Case.factory(3)

Output would look like this:

Case1
Case2
<class '__main__.Case1'> <class '__main__.Case2'>

Traceback (most recent call last):
  File "<string>", line 36, in <module>
  File "<string>", line 19, in factory
NotImplementedError: Unknown case: 3

Comments

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.