2
\$\begingroup\$

I have this project about using OOP in python. How to fully make use of OOP and use __init__(self)?

class Parent:
    name = "Player"
    lives = 3
    #display player running
    def run(self, name):
        self.name = name
        print "%s is running." %self.name

    #player will start to jump against enemy
    def jump(self, name):
        self.name = name
        print "%s jumps over enemy. TOINK TOINK" % self.name

    #player will start to grow
    def grow(self, name):
        self.name = name
        print "%s sarting to Grow" %self.name

For player1

#Mario
class Child1(Parent):
    name = "Mario"
    #special skill
    def blazingFire(self, name):
        self.name = name
        print "%s used his blazingFire" %self.name

For player 2

#Luigi
class Child2(Parent):
    name = "Luigi"
    #special Skill
    def blazingWind(self,name):
        self.name = name
        print "%s used his blazingWind" %self.name

Calling object

player = Parent()
player1 = Child1()
player2 = Child2()

#mario's turn
player1.run(mario)
player1.jump(mario)
player1.grow(mario)

Am I doing the right thing or there's a better way for this?

\$\endgroup\$
0

2 Answers 2

5
\$\begingroup\$
  • This is clearly Python2. To have better inheritance in Python2 you have to inherit from object. Inheriting from object is classed as a new-style class, and is better than old ones.

    class Parent(object):
        pass
    
    class Child1(Parent): # No need to inherit object again.
        pass
    
  • You don't use __init__... In your example code it may be bad to use it, since you are adding spells anyway. And you're overwriting self.name in your class anyway, so it's quite pointless.

    But lets say you wanted to have a default name for Child1, and you could assign it to something else, so you don't have to supply the name on every function. You can do almost exactly the same as you are doing on every function.

    def Parent(object):
        def __init__(self, name="Player", lives=3):
            self.name = name
            self.lives = lives
    
        def run(self):
            print "%s is running." % self.name
    
  • As for your print statements you should use str.format rather than the old 'sprintf'-like %. There are quirks with % and str.format is a lot stronger.

    print "{} is running.".format(self.name)
    

    The above is exactly the same as your above prints, but I'm sure at one point you will want to print the name and the lives. You can change the contents of the {}'s to allow you to use the name instead. Which allows for greater readability, as now we know '[player name] is running'.

    print "{0.name} is running.".format(self)
    

    Why stop there you can show lives to!

    print "{0.name} has {0.lives} live(s).".format(self)
    
  • As just saying 'use new style classes they are better than old style ones' isn't a compelling reason. There is something that you can do with new-style classes, which is calling it's parents functions. For example if we wanted to have the default name for Child1 as Luigi, you can do the following:

    class Child1(Parent):
        def __init__(name="Luigi", **args):
            super(Child1, self).__init__(name=name, **args)
    

    It's one good thing about new style classes, which get's improved in Python3 to:

    class Child1(Parent):
        def __init__(name="Luigi", **args):
            super().__init__(name=name, **args)
    

This will now change the 'calling object' code to:

player1 = Child1('Jay')
player2 = Child1('Joe')

player1.run()
player1.jump()
player1.grow()
player2.run()

Here is Parent and Child1 with the above changes, note I removed all the self.name = name's.

class Parent(object):
    def __init__(name="Player", lives=3):
        self.name = name
        self.lives = lives

    def run(self):
        print "{0.name} is running.".format(self)

    def jump(self):
        print "{0.name} jumps over enemy. TOINK TOINK".format(self)

    def grow(self):
        print "{0.name} sarting to Grow".format(self)

class Child1(Parent):
    def __init__(name="Luigi", **args):
        super(Child1, self).__init__(name=name, **args)

    def blazing_fire(self):
        print "{0.name} used his blazingFire".format(self)
\$\endgroup\$
3
  • \$\begingroup\$ I find the 0.name confusing personally, do you see it used instead of format(self.name) often? \$\endgroup\$ Commented Dec 11, 2015 at 10:24
  • \$\begingroup\$ @SuperBiasedMan I like 0.name as then you don't have to care about placment, or do format(name=self.name). But for a single varible it could very well be overkill... (I'm more thinking of when OP starts doing '{0.name} has {0.lives} live(s).') \$\endgroup\$ Commented Dec 11, 2015 at 10:35
  • 1
    \$\begingroup\$ I guess I personally like to do "{} blah blah {}".format(self.name, self.lives) even if it's more diverse. It's mostly style at that point though. \$\endgroup\$ Commented Dec 11, 2015 at 10:39
4
\$\begingroup\$

You definitely do need to use __init__ here. __init__ allows you to set attributes for a class that can then be used in functions or called on externally. It runs when a class is first created, so it's often used to set up the values that a class needs to run. Here's a very simple example:

class Player:

    def __init__(self, name):
        self.name = name

    def print_name(self):
        print("My name is " + self.name)


player1 = Player("Mario")
player2 = Player("Luigi")

print(player1.name)
# Mario
player2.print_name()
# My name is Luigi

You can see how this uses the self.name set up you had, but you don't need to pass name into the functions each time. Instead, when the class is created, you give it a name value that gets stored in the class to be called in later. (note that you don't technically need to assign these values with __init__, you could just do player1.name = "Mario" but that's much less neat than using __init__).

So in your case, let's set up your first class. I'd start by actually naming the class Player, not just calling it Parent and then giving it a name attribute that gets constantly overwritten. Then lives = 3 should also be in __init__ as putting it where you have it makes it a class attribute. Those are more commonly used for constants, or values shared across the whole class. __init__ is where you put the values that each individual instance of the class should have thir own value for:

class Player:

    def __init__(self, name):
        self.name = name
        self.lives = 3

    #display player running
    def run(self):
        print "%s is running." % self.name

    #player will start to jump against enemy
    def jump(self):
        print "%s jumps over enemy. TOINK TOINK" % self.name

    #player will start to grow
    def grow(self):
        print "%s starting to Grow" % self.name

Now you can see that you don't need to pass in name any more because it's part of the class. It can easily reference it with self.name instead. Also, I don't think you need separate classes for Mario and Luigi, since the only difference is that their function prints something different. Instead you could pass name and skill as two parameters and use them in the special_skill function:

class Player:

    def __init__(self, name, skill):
        self.name = name
        self.skill = skill
        lives = 3

    def special_skill(self):
        print "%s used his %s" % (self.name, self.skill)

Some other notes. You should look into docstrings. They make functions clearer and easier to read. You have comments on each function already, so it's good to turn them into docstrings.

Instead of using % to format, use str.format which is the new style for formatting. It's cleaner and easier, and has other advantages for down the line. For example you could turn

        print "%s used his %s" % (self.name, self.skill)

into

        print "{} used his {}".format(self.name, self.skill)
\$\endgroup\$
1
  • \$\begingroup\$ Thanks guys I followed all your suggestions and working fine. \$\endgroup\$ Commented Dec 14, 2015 at 1:50

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.