While our class works well, there are a few additional things we can do to make it better.
Add Security
One down side to our class is while we have class variables, anyone who knows our variable names can access them by specifying our object instance name and then the variable name, like in the example below:
my_dice.value = 25 # this should NEVER happen...but could
A simple solution is to put two underscores in front of the variable name when we use it in the class definition. When we do that, it blocks access to the variable from outside of the class/object. Now our class would look like the following:
import random
class Dice :
# all variables and methods are indented
def __init__(self) :
self.__value = random.randint(1,6)
def roll(self) :
self.__value = random.randint(1,6)
def get_value(self) :
return self.__value
This just adds a level of protection to our class, both in making sure only proper values are set, as well as making sure that if we change how things are stored internally, that it doesn’t break other people’s code.
Other languages use a keyword of private to limit access, but Python opts for the double underscore.
Creating Modules
We’ve already looked at how to use modules using the import command to import the random module.
Well we can create our own modules as well. Most of the time when using Object Oriented Programming, to keep things simple, we will put each class in it’s own separate file and then import that module.
This makes our code clearer as we are grouping it based upon function, and making easier to update, especially when we have multiple people working on the same project. Each can be assigned one or more classes, and work on those files without interfering with other people.
To create a module, you will need to copy the class and all of it’s methods into a new file. From our previous example of Dice, we might put all of that into a file called dice.py.
import random
class Dice :
# all variables and methods are indented
def __init__(self) :
self.value = random.randint(1,6)
def roll(self) :
self.value = random.randint(1,6)
def get_value(self) :
return self.value
In our Application, we’ll import that module by using the import command.
import dice
def main() :
my_dice = dice.Dice() # create an instance of the dice
for num in range(25) :
my_dice.roll()
print('Roll', str(num +1) + ':', my_dice.get_value())
main()
Notice that we need to specify the module name, and then the class constructor when we build our class. This way Python knows where to find the constructor. Once it is assigned to a variable (my_dice
) notice that we don’t need to use the dice.
prefix any more.
The name you use as the prefix is directly related to the file name which you import, which is name of the file, minus the .py.
Extending the use of the Class
We’re going to extend the usefulness of the class by allowing you to have more than six sides to your dice. This allows you to reuse the class in more locations.
However, when we refactor the class, we don’t want to force a person to edit their original code. So we’re going to add an optional parameter to the constructor method. If it isn’t called, then we will give it a default value of 6, like is currently being used. However, then can pass in an additional value to the constructor, which will allow it.
To have this parameter, after self (which has to the be the first parameter) you give it a parameter name, and then specify what the default value would be, as you see below:
class Dice :
# all variables and methods are indented
def __init__(self,sides = 6) :
We will then store one additional class level variable which will store this information, so we can use later.
class Dice :
# all variables and methods are indented
def __init__(self,sides = 6) :
self.max_sides = sides
Now we can use self.max_sides within our random function to help us get values based upon the number of sides our dice will be. By default it is 6, so it won’t break anything that we’ve already written.
import random
class Dice :
# all variables and methods are indented
def __init__(self,sides) :
self.max_sides = sides
self.value = random.randint(1,self.max_sides)
def roll(self) :
self.value = random.randint(1,self.max_sides)
def get_value(self) :
return self.value
Improving our Basic Python Class was originally found on Access 2 Learn