fbpx

Programming Concepts : Object Oriented Programming (OOP) in Python

“Class” in Python

When initializing a class, (parenthesis) after class name is optional. It’s convention to capitalize the first Letter of the class name. Not necessary for code to work.

What goes under def __init__ are the attributes for that class. For example.

Class Car:
  def __init__(self, car_size, car_weight, car_price):
    self.size = car_color
    self.weight = car_weight
    self.price = car_price

def __init__ above defines the attributes of a generic car. These can be used to create the attributes of a specific car. def __init__ is a built in python method and python knows to use it to generate a new instance of a specific Car() object.

Self tells python to where to locate the object in question in the computer’s memory. Self is a convention, but any other term could be used as long as there is consistency. Better to use Self to avoid confusion. Self stores the attributes and make them available through out the class. Think of it like a dictionary that holds the attributes and the attribute values. Self also gives you access to the class method, not just the attributes.

In the example below, change_price method was initialized with self so that this method will have access the price attribute defined in the __init__ method above as well as the other attributes. Always use Self as the first argument to access it within your method.

class Car:
  def __init__(self, car_size, car_weight, car_price):
    self.size = car_size
    self.weight = car_weight
    self.price = car_price
    
    
# Replace whatever prior price the object had for price with the new value defined in new_price.     
  def change_price(self, new_price):
    self.price = new_price
    
    

Instantiating and using the Class above.

new_car = Car(4, 3000, 40000)
# to access the values instantiated above, 
print(new_car.size)
print(new_car.weight)
print(new_car.price)
# to access the change_price method. 
new_car.change_price(50000)
# to access the new price of the car.
print(new_car.price) # should print 50000

Function vs Method.

Function – defined with def name() keyword OUTSIDE of a class

Method – defined with def name() keyword INSIDE of a class.

Get and Set Methods.

Syntax like this allows you to access and change variable directly.

new_car.price = 10000
print(new_car.price) # will print 10000

Get Method = obtain attribute value. Set Method = change attribute value.

class car:
    def __init__(self, car_color, car_size, car_style, car_price):
        self._price = car_price
    def get_price(self):
      return self._price
    def set_price(self, new_price):
      self._price = new_price

In other languages, underscore before price _price is indication that price is a private variable to be used only with get&set methods. But, python doesn’t have any concept of private & public variable. So, you could use it or not. Python will treat self._price same as self.price unlike other languages like C++ and Java.

Private variable will prohibit direct access to the attribute like this…new_car._price = 10000. So, you cannot set the value of the attribute of price through direct access. But, that’s not the case with python. In python, you can set the price directly as shown above.

Despite the lack of private variable enforcement, python programmers still use _name to clarify that an attribute should only be used with get & set methods even though there is nothing preventing anyone from accessing the _name directly.

Get & Set methods work beautifully for situation where you need to do more than set a defined value or just retrieve the data input. Assuming you need to put constraints on the input value for setting_method and you need to do some calculations before retrieving the data, then Get&Set methods will allow you to code those things in.

This example from this blog does a beautiful job of explaining when get&set methods might be useful.

class P:
    def __init__(self, x):
        self.set_x(x)
    def get_x(self):
        return self.__x
    def set_x(self, x):
        if x < 0:
            self.__x = 0
        elif x > 1000:
            self.__x = 1000
        else:
            self.__x = x

Getters and Setters method allows you to change the implementation of the code without changing the user_interface which will prevent things from breaking if you need to change the code.

Private vs Public Attributes.

To define a private method that can’t be access by users of your class, add __ in front of the class name. For example

class P:
    def __init__(self, x):
        self.__set_x(x)
    def __get_x(self):
        return self.__x
    def __set_x(self, x):
        if x < 0:
            self.__x = 0
        elif x > 1000:
            self.__x = 1000
        else:
            self.__x = x
    x = property(__get_x, __set_x)

To make an attribute private in python, use the @property attribute. Here is an example of how to use property decorator.

class OurClass:
    def __init__(self, a):
        self.OurAtt = a
    @property
    def OurAtt(self):
        return self.__OurAtt
    @OurAtt.setter
    def OurAtt(self, val):
        if val < 0:
            self.__OurAtt = 0
        elif val > 1000:
            self.__OurAtt = 1000
        else:
            self.__OurAtt = val
x = OurClass(10)
print(x.OurAtt)

Detailed example of how to use python property class when writing python class.

Private attributes indicates the attribute could only be access within the class (members of the class) and not outside the class. So, an attribute you will write to use in your class but your end users won’t need to use it. Public attributes can be used within and outside your class by you or your end users.

How to access private attributes in python.

In python, private attribute can be defined by using double underscore (__name). To access private attribute outside the class, here is how to do it.

class Test:
  def __init__(self, price, shoe, color):
    self.price = price #public
    self.__shoe = shoe #private
    self._color = color # not private
    
  def what(self):
    print('price - ', self.price)
    print('shoe - ', self.__shoe)
    print('shoe - ', self.__color)
    
  
x = Test(40, 'running_shoes', 'red-blue')  
print(x.color) # AttributeError: 'Test' object has no attribute 'color'
print(x._color) # prints 'red-blue'
print(x.price ) # prints 40 
print(x.shoe) # prints AttributeError: Test instance has no attribute 'shoe'
# even if you try
print(x.__shoe) # prints AttributeError: Test instance has no attribute 'shoe'

So, in the most basic sense, the attribute __shoe is private, but it can still be accesses.

# to access private attributes in python, 
print(x._Test__shoe) # will give you "running_shoes"
# also doing 
x.what() # will also yield the expected results. 

Go to the next page to learn about python magic methods.

Leave a Comment

Scroll to Top