Learn Python: Functions and Object Orientation
In this section, we will learn about Function and Object Orientation in detail with examples and how they are useful in real-time programming.

Functions
One of the fundamentals of any programming language is that there are often repeated elements. You can cut and paste code from one section to another, but this looks messy! but what happens when you need to update the particular part of the program, for a small part of programs this is unlikely to generate any significant overhead, but as the size and complexity of the program increases, so does the time required to modify and update essentially the same piece of code over and over. Duplication also runs the risk of introducing additional syntactic, logical, and typographical errors. Imagine duplicating a sequence that contained a simple typing mistake would trace every single instance to isolate the problem. This is where functions
solve all your problems. By placing the repeated code into a function you isolate that code sequence and provide easier access to improve the code or isolate bugs. This method of taking repeated pieces of code and placing them into a function is called abstractions
. In general, a certain level of abstraction is always useful it speeds up the programming process reduces the risk of introducing errors, and makes a complex program easier to maintain. We know that Python has 3 basic levels of abstraction.
1. A program can be split into multiple modules.
2. Each module contains multiple statements.
3. Each statement operates on objects
Function Definition and Execution
The general format for creating new functions is as follows:
def NAME(ARG1[,...]):
STATEMENT BLOCK
[return VALUE]
The NAME
value should follow the same rules as object names:
- Functions must begin with an underscore or letter and may contain any combination of letters, digits, or underscores. You cannot use any other punctuation characters.
- Functions are case sensitive, combine and Combine are two different function names. However, you should avoid creating functions of the same name but in different cases.
- You cannot use a reserved word for a function name but remember the case-sensitive rule.
The following example is a simple function that calculates the area of a circle based on the radius supplied:
def area(radius):
area = 3.141*(pow(radius, 2))
return area
To use the area function, just call with an argument:
print(area(2))
which returns 12.564
Note the precision in the result is identical to the precision you use for the value of pi. If you supply a value with higher decimal precision, the return value is also of higher precision. The statement
print(area(3.141592654))
which returns 31.0004274319
Finally, unlike other languages, functions within Python can be defined on the fly, you can create a function anywhere within the normal execution of a program. The following code is perfectly valid:
if (message):
def function():
print("Hello")
else:
def function():
print("Goodbye")
It opens up all sorts of possibilities, especially when it comes to the development of objects and methods. The scoping, argument definition, return values, and the methods for calling functions all have extended feature sets within the Python language so let's look at each feature individually.
Scoping
Python uses the concepts of namespaces
in order to store the information about objects and their location within an application. Namespaces are specific to a particular level of abstraction. There are individual namespaces for the functions and modules and there's a special namespace for the built-in functions and objects. Scoping within Python follows these basic rules:
1) Each Module has its own scope. This means that multiple modules have their own scope and therefore their own namespaces.
2) The enclosing module for a function is called the global scope. This is the location of objects created at the top level of a module file.
3) New function definitions create a new scopes; the scopes are unique to the function.
4) New objects are assigned to the local scope unless declared otherwise. Any variable or function that is defined will be a member of the local scope unless you declare it global with the global keyword.
5) Arguments to a function are defined within the local function scope.
The scoping rules mean that objects created within a function do not interfere with identically named objects in the module(global) or built-in namespaces. Our area
function is a good example:
def area(radius):
area = 3.141*(pow(radius, 2))
return area
The area function
is global, because, it's defined within the top-level of the module. The area variable
is defined within the local scope of the area
function. This means that although they have the same name, they do not interfere with each other.
Making Objects Global
There are occasions when you want to assign the value of a variable within a function, but you have it modify the global variable instead of creating a new one. The traditional method for this is to predeclare the variable before the function is called:
name = 'unknown'
def set_defaults():
name = 'Python'
set defaults()
print(name)
However, this doesn't work in Python because the moment you assign the name
variable within the function, Python creates a new variable within the local scope. To get around this, you need to use the global
keyword to define which variables you want to use in this way. The global
keyword tells Python to create a local alias to the global variable. For example, if you modify the preceding script.
name = 'unknown'
def set_defaults():
global name
name = 'Python'
set defaults()
print(name)
This function works what you expect, it prints Python. The global
keyword also creates objects within the global namespace if they don't already exist, as in the following example.
def set_defaults():
global names, address
name = 'Python'
address = 'Python@py.com'
set_defaults()
print('Name : ', name, 'Address : ', address)
Output:
Name : Python Address : Python@py.com
Object Orientation
Object Orientation programming is a mechanism that allows you to create intelligent variables called objects
that can be used to store complex structures that not only hold data but also know what functions and operations can be performed on them. The system work through the creation of a class
. A class
defines the format and structure of individual objects called instances
and defines the functions that operate on those objects.
Creating a class
Creating a new class in Python requires the class statement, which works like any other block definition in Python, everything contained within the class
block becomes a part of the class you're defining. The format for creating a new class looks like this:
class CLASSNAME([CLASS_PARENT, ...]):
[STD_ATTRIBUTES]
. . .
def METHOD(self, [METHODARGS]):
. . .
CLASSNAME is the name of the class that you want to create. Python uses the same basic rule for classes as for any other object. However, as a general rule. user-defined class names are often in title case to distinguish them from the standard library class supplied with Python. The parentheses following the class are optional and are used only for specifying any classes from which you inherit attributes. The STD_ATTRIBUTES
is the default attributes that you want to apply to all instances of this class. These are given static values at this point, unlike the attributes that you might set during the initialization. For example, you can create the Account class as follows:
class Account:
account type = 'Basic'
def __init__(self, name, balance):
self.name = name
self.balance = balance
def deposit(self, value):
self.balance += value
def withdraw(self, value):
self.balance -= vlaue
To create a new object based on our new class, you call the class as if it is a function:
bank = Account('HSBC', 2000)
Class Methods
Class methods are in fact just functions that have been defined within a scope of a given class. The only difference between a class method and an ordinary function is that the first argument to any class method is the object on which it is operating. For example, when you call the deposit()
method on an instance,
bank.deposit(1000)
Python actually calls the deposit()
function within the Account
class, supplying the object as the first argument (typically self
) and the argument you supplied to the deposit function as the second argument:
Account.deposit(bank, 1000)
This enables you to access the object attributes and update their values from within the function. Without self-argument, you'd never be able to modify the object. You can see this more clearly in the following simplified class and method definition of the Account
class:
class Account:
account_type = 'Basic'
def __init__(self, name, balance):
self.name = name
self.balance = balance
def deposit(self, value):
self.balance += value
Object Constructors
The __init__() function is the special name you should use within a class for the constructor. This function is called when you create a new object based on this class. In below example
def __init__(self, name, balance):
self.name = name
self.balance = balance
The method accepts two arguments: the name of the account you're creating and the balance of the account. These are used to initialize the values of the object's attributes. What this actually does is call:
bank = Account.__init__('HSBC', 2000)
The new variable, the bank is an object or an instance of the Account
class. You can get the balance of the account by accessing the balance
attribute.
Object Destructors
All class instances have a reference count for the number of times they have been referenced: this count can include, for example, each name that refers to that instance, each time the instance is included as part of a list, tuple, or dictionary and so on. When the reference count reaches 0, the instance is automatically destroyed, freeing up the memory used to hold the object data.
If you want to define a custom sequence for destroying an object(a destructor function) you need to define the __del__() method. Python automatically calls the __del__() method when an object needs to be destroyed. All objects inherit a built-in __del__() method if the class does not define its own. Because of this, most basic objects, such as the example created here, don't require the __del__() method.
Class Inheritance
The Parentheses following a class name are used by Python to identify the classes from which you inherit attributes and methods. As an example below where two classes are defined CreditCard
and Bank Account
, each of which inherits artifacts from the base class Account
.
class BankAccount(Account):
account_type = 'Bank Account'
def __init__(self, name, balance):
self.name = name
self.balance = balance
def __init__(self, name, balance, accno, sortcode, bankname):
Account.__init(self, name, balance)
self.accno = accno
self.sortcode = sortcode
self.bankname = bankname
class CreditCard(Account):
account_type = 'Credit Card'
def __init(self, name, balance, accno, expiry, limit, rate):
Account.__init__(self, name, balance)
self.accno = accno
self.expiry = expiry
self.limit = limit
self.rate = rate
def withdraw(self, amount):
if abs(self.balance-amount)
Note that the withdraw()
method within the CreditCard
the class overrides the default method defined in the Account
class. Note also that an exception was added that is raised when you try to withdraw money beyond your limit. If you now create a CreditCard
instance, notice that you can use the withdraw()
and deposit()
methods:
>>> visa = CreditCard('HSBC', -1000, '123456789', '02/99', 8000, 18)
>>> visa.deposits(500)
>>> visa.balance
-500
>>> visa.withdraw(2000)
>>> visa.balance
-2500
One thing to note is that when you create an instance of a class that inherits from another class, the constructor for the new class does not automatically call the constructor method for the base class, hence the need for the following line in the constructor for both the BankAccount
and CreditCard
classes:
Account.__init__(self, name, balance)
This directly calls the constructor for the base class during the name and balance supplied to the class constructor to initialize an instance within the current class. Note that you don't have to call the base class constructor immediately if you don't want to, but it's probably a good idea.