Python matplotlib – 2

In this article:

  1. Plotting more sets of data in the same graph
  2. A graph with categorical variable

1. Plotting more sets of data in the same graph

Lets plot two functions
y1=x2 + 1, y2= x3+2*t
X values are between 0 and 10

Code which solve the problem:

import numpy as np
import matplotlib.pyplot as myplot
t = np.arange(0., 10., 0.25)
myplot.plot( t, t**2+1, 'r>') myplot.plot( t, t**3+2*t, 'b*')
myplot.show()

Code explanation:
t = np.arange(0., 10., 0.25)
this generate x coordinate values. First argument 0. is the start value.
Second argument 10. is the end value. Third argument is the step between value.
Means generated values by np.arange are 0., 0.25, 0.50, 0.75, 1, 1.25 etc.

Plot function have 3 arguments this time, first two was explained in previous post.
Third argument is plot "format string", which describe colour used for draw and character.
Thus for myplot.plot( t, t**2+1, 'r>')
third argument 'r>' will draw plot in red colour ('r') using triangle_right marker ('>).
Documentation about all markers supported by plot are in matplotlib.pyplot.plot, section "Format Strings".

Is important to retain that in plot "format string" first character is plot colour and the second character is type of marker.

For myplot.plot( t, t*3+2t, 'b') third argument 'b' will draw plot in blue ('b') and the marker is '*'

Output from code is in below image:

Plotting more sets of data in the same graph

2. A graph with categorical variables

Sample problem for this case: we have population
spread in 4 group ages:
years_18_30, medium income is 2800
years_31_45, medium income is 4100
years_46_60, medium income is 4500
years_60_plus, medium income is 3800
We need to plot categorical variable age/income for this.

Code is:

import matplotlib.pyplot as myplot
ages=['year_18_30', 'year_31_45', 'year_46_60', 'year_60_plus']
income = [2800, 4100, 4500, 3800]
myplot.figure(figsize=(5, 5))
myplot.subplot(111)
myplot.bar(ages, income)
myplot.show()

This time graph is draw in a figure, created by
myplot.figure(figsize=(5, 5))
Size of figure is width 5 inches, heigh 5 inches.

Graph is a bar graph type, draw with
myplot.bar(ages, income)

In code Similar output we used figure and subplot, similar output is obtained
without those with code:

import matplotlib.pyplot as myplot
ages=['year_18_30', 'year_31_45', 'year_46_60', 'year_60_plus']
income = [2800, 4100, 4500, 3800]
myplot.bar(ages, income)
myplot.show()

Python matplotlib – 1

In this article:

  1. A simple graphic with pyplot
  2. Using lists for graphic coordinates
  3. A graphic with many lines
  4. Using tuples for graphic coordinates
  5. What happen when lists or tuples for coordinates have different size?
  6. Save graphic in a file

1. A simple graphic with pyplot

Most simple graphic with matplotlib is plotting with pyplot interface:

import matplotlib.pyplot as myplot
myplot.plot([1, 5], [2, 12])
myplot.show()

This show graphic like below:

Simple graphic with mathplotlib pyplot.

From image result that pyplot draw a line between two points (1,2) and (5,12)

2. Using lists for graphic coordinates

Arguments for "plot" in myplot.plot([1, 5], [2, 12]) are 2 lists:
l1 = [1, 5]
l2 = [2, 12]

The same graphic is obtained using:

import matplotlib.pyplot as myplot
l1 = [1, 5]
l2 = [2, 12]
myplot.plot(l1, l2)
myplot.show()

In this case line draw is between
point 1 with coordinates:
x=first element of list l1, or l1[0]
y=first element of list l2, or l2[0]
point 2 with coordinates:
x=second element of list l1, or l1[1]
y=second element of list l2, or l2[1]

3. A graphic with many lines

If lists l1 and l2 have more elements, plot will draw line(es) between appropriate points. For example:

import matplotlib.pyplot as myplot
l1 = [1, 3, 5]
l2 = [2, 4, 12]
myplot.plot(l1, l2)
myplot.show()

Code will draw:

A pyplot graphic with many lines

In this case lines are between points that have coordinates:
(1,2), (3,4), (5,12)
or
(l1[0],l2[0]), (l1[0],l2[0]), (l1[0],l2[0])

4. Using tuples for graphic coordinates

The same graphic is obtained if we use tuples, i.e. code:

import matplotlib.pyplot as myplot
t1 = (1, 3, 5)
t2 = (2, 4, 12)
myplot.plot(t1, t2)
myplot.show()

Lists or tuples can have more elements, it is important that those to have
the same number of elements.

5. What happen when lists or tuples for coordinates have different size?

If we try with different elements, for example code:

import matplotlib.pyplot as myplot
l1 = [1, 3, 5]
l2 = [2, 4, 7, 12]
myplot.plot(l1, l2)
myplot.show()

this will fail with error:
ValueError: x and y must have same first dimension, but have shapes (3,) and (4,)

6. Save graphic in a file

Command myplot.show() display effectively resulted graphic.
Using savefig() graphic is saved in a file for example:

import matplotlib.pyplot as myplot
l1 = [1, 3, 5]
l2 = [2, 4, 12]
myplot.plot(l1, l2)
myplot.savefig("C:\tmp\fig1.png")

Here savefig method is used with only one parameter, the file path.
Method savefig have many more parameters, like here.
Above code will save graphic in file C:\tmp\fig1.png

MySQL-Python – 5 Logging and MySQL Connector

This is a continuation from previous post MySQL-Python - 4.

In this page:


1. About logging

Logging activity for MySQL connector use default Python logging features. By default events with level WARNING are logged and are printed to terminal where we run, i.e. sys.stderr 

Configuring logging, we can change logged events level and we can print messages to other destination than stderr.


2. Sample code for classical logging

Below is a sample code for logging used in case when MySql Connector is used with insert. Use can be similar for other MySQL connector usecase. 

import logging

import datetime

import mysql.connector


#--this is code for loggers

logger = logging.getLogger("mysql.connector")

logger.setLevel(logging.DEBUG)


formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s- %(message)s")


# create console handler named stream_handler

stream_handler = logging.StreamHandler()

# add formatter to stream_handler

stream_handler.setFormatter(formatter)

# add  console handler  stream_handler to logger

logger.addHandler(stream_handler)

# create a file handler

file_handler = logging.FileHandler("conn_log.log")

# add formatter to file handler

file_handler.setFormatter(formatter)

# add  file handler to logger

logger.addHandler(file_handler)


#---this is code where mysql connector is used

connection = mysql.connector.connect(user='u2024', password='password1234', host='localhost', port=3306, database='sakila')

logger.debug('user u2024 logged')

cursor = connection.cursor()

logger.info('mysql.connector created cursor')


SQL_insert_actor = ("INSERT INTO actor (first_name, last_name, last_update)"

            "VALUES  (%s, %s, %s)")

values_for_actor = ('NICK','WALKEN', datetime.date(2023, 12, 16))

cursor.execute(SQL_insert_actor, values_for_actor)

# commit to the database

connection.commit()

logger.info('mysql.connector entry inserted in DB')


cursor.close()

connection.close() 


3. Code comments

First we defined a logger using logger = logging.getLogger("mysql.connector"), here mysql.connector is the logger name, it can be anything, we  named it  mysql.connector for visibility.

Change log level to DEBUG using logger.setLevel(logging.DEBUG)

Permitted log level are here

Line: formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s- %(message)s") 

define how log record will appear. This line is not mandatory, if we not use it, by default will be used string like '%(message)s' which means only the message will be in log record.

In our example we use a formatter object  thus we will display in log line: time, name, log level of the message and message itself. More about possibility for format message in formatter-objects


Next lines:

# create console handler named stream_handler

stream_handler = logging.StreamHandler()

# add formatter to stream_handler

stream_handler.setFormatter(formatter)

# add  console handler  stream_handler to logger

logger.addHandler(stream_handler)


create a stream handler that is added to logger, this stream handler is for logging to console, means lines for example that appear if we run python script in command prompt, or lines that appear on the screen as we will see when run in PyCharm


Lines:

file_handler = logging.FileHandler("conn_log.log")

# add formatter to file handler

file_handler.setFormatter(formatter)

# add  file handler to logger

logger.addHandler(file_handler)


those create a file handler and add it to logger, those lines are responsible for what will be written in log file named "conn_log.log".


All the lines that follow after 

#---this is code where mysql connector is used

are to exemplify. From mysql connector point of view, those contain lines for inserting in DB. 

Between those lines, we added lines for logging, those contain logger.debug or logger.info

For example line like 

logger.debug('user u2024 logged')

will sent message 'user u2024 logged' with proper formatting, to console or file.


4. Sample logging output 

Below is an image with sample code run in Pycharm.


Logging in mysql connector, PyCharm


We see with red lines in output log lines from console handler defined prior. 

In  file "conn_log.log" appear also lines, this time from file handler. Below is how file looks like: 

Logging in file

MySQL-Python – 4. Insert and Update in MySQL DB with mysql.connector

This is a continuation from previous post MySQL-Python - 3.

In this page:

Insert

For insert sample, we will add a record in actor table from sakila sample database. We need to insert in actor table a record for person named NICK WALKEN which have last activity December 16, 2023

First let's see how records from actor table looks like.  For this opening MySQL 8.0 Command Line Client there is:

MySQL Command Line select sample


After we see record structure we can imagine how SQL insert will looks like and maybe test this in MySQL 8.0 Command Line Client.

Insert is: 

INSERT INTO actor (first_name, last_name, last_update) VALUES ('NICK', 'WALKEN',STR_TO_DATE('December 16, 2023', '%M %d,%Y'));

After run above select we verify result using a SELECT like below: 

SELECT * FROM actor WHERE first_name LIKE 'NICK' AND last_name LIKE 'WALKEN';

And we will obviously delete it because we will run insert once verified in python code later. To delete: 

DELETE FROM actor WHERE first_name LIKE 'NICK' AND last_name LIKE 'WALKEN';


MySQL Command Line insert sample


Sample Code for INSERT

import datetime

import mysql.connector


connection = mysql.connector.connect(user='u2024', password='password1234', host='localhost', port=3306, database='sakila')

cursor = connection.cursor()


SQL_insert_actor = ("INSERT INTO actor (first_name, last_name, last_update)"

            "VALUES  (%s, %s, %s)")

values_for_actor = ('NICK','WALKEN', datetime.date(2023, 12, 16))

cursor.execute(SQL_insert_actor, values_for_actor)


# commit to the database

connection.commit()


cursor.close()

connection.close()


Below is the same code executed in PyCharm

MySQL insert in PyCharm


Comments about code: 

Flow is similar with select flow from "MySQL-Python - 3", i.e. there is connection object, cursor object, SQL statement this time is in string named SQL_insert_actor. In current code appear new commit() method, because having an insert that modify data, we need to commit to DB. Then follow known cursor and connection close. 

Values that are used in insert are passed using notation similar with that from select with parameter, there is "VALUES  (%s, %s, %s)"

To "populate" values, we put those in a tuple named values_for_actor using 

values_for_actor = ('NICK','WALKEN', datetime.date(2023, 12, 16))

after that when run cursor execute: 

cursor.execute(SQL_insert_actor, values_for_actor)

values from tuple i.e. 'NICK','WALKEN', datetime.date(2023, 12, 16) go one by one and will replace %s from SQL statement named SQL_insert_actor

Observation: when we checked with select statement actor table data, we see there column actor_id, this is not in VALUES because it is an AUTO_INCREMENT column.


Update

We propose to update NICK WALKEN record from actor table to change last_update to be December 19, 2023

Sample code for UPDATE:

import datetime

import mysql.connector


connection = mysql.connector.connect(user='u2024', password='password1234', host='localhost', port=3306, database='sakila')

cursor = connection.cursor()


SQL_update_actor = ("UPDATE actor SET last_update=%s WHERE first_name LIKE 'NICK' AND last_name LIKE 'WALKEN'")

tochange_last_update = (datetime.date(2023, 12, 19), )

cursor.execute(SQL_update_actor, tochange_last_update)


# commit to the database

connection.commit()


cursor.close()

connection.close()


MySQL update in PyCharm


We can check if update was ok, using select


Update Check


Comments about code:


- Code is similar with previous sample, main difference is SQL statement in this case is SQL_update_actor and the tuple tochange_last_update that we use to pass parameter to update, here tochange_last_update is a tuple with only one element, means this is why we not have (datetime.date(2023, 12, 19)) means heaving (datetime.date(2023, 12, 19), )  

Comma from the end is for tuple with one element. 


- Passing parameter to SQL statement, here SQL_update_actor is possible via %s, means something like replacing 


SQL_update_actor = ("UPDATE actor SET last_update=%s WHERE first_name LIKE 'NICK' AND last_name LIKE 'WALKEN'")

tochange_last_update = (datetime.date(2023, 12, 19), )

cursor.execute(SQL_update_actor, tochange_last_update)


with 

SQL_update_actor = ("UPDATE actor SET last_update=datetime.date(2023, 12, 19) WHERE first_name LIKE 'NICK' AND last_name LIKE 'WALKEN'")

cursor.execute(SQL_update_actor)


will not work. In this case  datetime.date(2023, 12, 19) from inside SQL_update_actor will be treated like a routine from SQL point of view and _mysql_connector will give error 


- parameter is expected to be tuple, list or dictionary

Means trying to use 

tochange_last_update = datetime.date(2023, 12, 19)

 (and not tochange_last_update = (datetime.date(2023, 12, 19), ) )

will fail with error: 

mysql.connector.errors.ProgrammingError: Could not process parameters: date(2023-12-19), it must be of type list, tuple or dict

MySQL-Python – 3. Accessing MySQL DB with mysql.connector


This is a continuation from MySQL-Python – 2 where we discussed about users and database.


In this page:


Installing mysql.connector


First we need to install package mysql.connector, for this in command prompt we need to use pip.


We will use for new package install: 

pip install mysql-connector-python


Or if page is already installed, is recommanded to upgrade it with: 

pip install mysql-connector-python --upgrade


Install mysql connector in python

As we can see in this PC package is already  installed. 


Using select with mysql.connector

Sample code is below:

import mysql.connector


connection = mysql.connector.connect(user='u2024', password='password1234', host='localhost', port=3306, database='sakila')

cursor = connection.cursor()


SQLquery = "SELECT  rental_id, customer_id, rental_date FROM rental "


cursor.execute(SQLquery)


for ( rental_id, customer_id, rental_date) in cursor:

  print("Rental with id: {}, done by customer id: {} was rented on {:%d %b %Y}".format(customer_id,  rental_id, rental_date))


cursor.close()

connection.close()


Python MySQL base code


Comments about code: 

First we create a connection object using method mysql.connector.connect which have like parameter user/password, MySQL host, MySQL port and database to which we will open connection. 

Then we create a cursor object using cursor = connection.cursor(), in which we will fetch later, data from table. 

To execute cursor first we need SQL statement, this is stored in a string named SQLquery

There is: SQLquery = "SELECT  rental_id, customer_id, rental_date FROM rental "

Once we have SQL statement to fetch (or to get ) data in cursor we use execute method: 

cursor.execute(SQLquery)

The for loop is used to iterate over cursor and to display lines (records) one by one.


Select with parameter

Code is similar, Below is sample code for this:

import mysql.connector


connection = mysql.connector.connect(user='u2024', password='password1234', host='localhost', port=3306, database='sakila')

cursor = connection.cursor()


SQLquery = ("SELECT  rental_id, customer_id, rental_date FROM rental "

         "WHERE rental_date BETWEEN %s AND %s")


rental_date = datetime.date(2005, 8, 22)

return_date = datetime.date(2005, 8, 25)


cursor.execute(SQLquery, ( rental_date, return_date))


for ( rental_id, customer_id, rental_date) in cursor:

  print("Rental with id: {}, done by customer id: {} was rented on {:%d %b %Y}".format(customer_id,  rental_id, rental_date))


cursor.close()

connection.close()

Python MySQL using select with parameter


Comments about code:

SQLquery string is changed, for select with parameter(s) we added in WHERE clause BETWEEN %s AND %s, here "%s" instruct interpreter that for the parameter we will provide a value. Parameters in this case are rental_date and return_date value for those is like 'YYYY,MM,DD'. To provide date we use from datetime module date object datetime.date, this represent a naive date (it is a date that not contain information about time zone, daylight, etc., from simple reason we not need for this application this information).

In execute method we provide parameters  rental_date, return_date now syntax is 

cursor.execute(SQLquery, ( rental_date, return_date)) in this case rental_date will replace first "%s" and return_date by the second "%s" from discussed SQLquery.

The rest of the code is similar. 

MySQL-Python – 2. Database and user

This is continuation from MySQL-Python – 1 post where we installed MySQL server. 


In this page:


Accessing database from MySQL Workbench

We will access Sakila sample database with Python. 

First to remeber, when we installed MySQL we choose to install and configure "Samples and Examples". This option installed Sakila database.


We can see it fast, that it is on our server, either using in Windows 11: All Apps > MySQL > MySQL Workbench 8.0 CE

Click on Local instance


MySQL Workench


If password requested for root, type it, then MySQL Workbench will open and display Administration in Navigator panel. 

Clik Schemas and we will see sakila db.


MySQL Workench


And clicking further on Tables we see those. 

MySQL Workench



Accessing database using MySQL Command Line Client


Similar we can see sakila database using MySQL Command Line Client

In Windows 11: All Apps > MySQL > MySQL 8.0 Command Line Client

MySQL Command Line 1

When prompt to enter password, enter root password.

 

Now we can use sakila database, for example type USE sakila;

then we can execute a sql command for example select how many lines are in actor table. 

MySQL Command Line 2


Observation: if sakila database was not installed initial when MySQL was installed 

it can be added later, for example follow procedure like here.


In both cases from above user was root. In real life when access databases in applications we use a normal user (a user with fewer privileges, from security reason).  Below is the procedure to create the user.


Creating user from MySQL Command Line Client

Lets suppose we need to create user u2024, after you login to  MySQL Command Line tool like root run "SELECT user FROM mysql.user;" to check if user already exist. 

MySQL Command Line select user 3


u2024 is not in the list. 

To create it run: CREATE USER 'u2024' IDENTIFIED BY 'password1234';

MySQL Command Line create user

After create user we use again "SELECT user FROM mysql.user;" which confirm that user is created. 


Next step is to grant privileges to u2024 in sakila database for this we run:

GRANT SELECT,CREATE,INSERT,DELETE,UPDATE,EXECUTE,ALTER,DROP,LOCK TABLES,CREATE TEMPORARY TABLES ON sakila.* TO 'u2024';

MySQL Command Line grant 4


To test user, open a command prompt , change directory to folder where mysql is:

cd "C:\Program Files\MySQL1\MySQL Server 8.0\bin"

then connect with that user: mysql -u u2024 -p 

MySQL Command Line connect with user


Further we verify if we run commands, for example select. 

MySQL Command Line select

Run  quit; to exit from MySQL Command Line


Creating user from MySQL Workbench CE

Lets suppose we need to create user u2023.

After open MySQL Workbench CE and use root to connect we have this screen.

MySQL Workbench CE Users and Privileges


Click on "Users and Privileges" there is:

MySQL Workbench CE Users and Privileges 1

click "Add Account


MySQL Workbench CE Add User

Write details as in underlined with red edit boxes, then clik Account Limits


MySQL Workbench CE Account Limits

Here we can set limits for user connections, updates and queries. 

Click Administrative Roles.


MySQL Workbench CE Administrative Roles

here we can add administrative roles used for administer server. We not check something here because u2023 is just a user with limited privileges. 

Click Schema Privileges.


MySQL Workbench CE Schema Privileges

To add privileges for sakila schema click "Add Entry..."


MySQL Workbench CE Schema Privileges 2

Here select schema sakila then click Ok.


MySQL Workbench CE Schema Privileges

Here select rights, similar with what we granted previous for u2024

Click Apply.


User u2023 is created. 

MySQL Workbench CE Schema Privileges 4

MySQL-Python – 1. Installing mySQL

In this page: 


Downloading MySQL

Currently MySQL have 3 flavors: 

  • MySQL Enterprise Edition
  • MySQL NDB Cluster CGE
  • MySQL Community (GPL)

In current article we will discuss how to install MySQL Community (GPL) edition on Windows 10 or 11. 

To download installer first search for "MySQL download" or just load https://www.mysql.com/downloads/

MySQL download

Click on link "MySQL Community (GPL) Downloads"


mySQLDownload-2

Click on link "MySQL Installer for Windows"


MySQL Download 3

Select mysql-installer-community-8.0.35.0.msi to download installer local on pc (or select mysql-installer-web-community-8.0.35.0.msi to start installation directly from web)


MySQL Download 4

Specify location or path where to save file then click Save


MySQL install

After file mysql-installer-community-8.0.35.0.msi download finish, double click on it.


mySQL custom install-5

There are four setup type: 

  • Server only
  • Client only
  • Full
  • Custom

We choose Custom setup because it permit to select components that we desire to install.

After we choose setup type we select the products to install.


MySQL select products

Regarding to selected products it is desirable to mention that:

  • MySQL Workbench is a graphical tool which can be used for working with SQL commands.
  • MySQL Shell is a command prompt tool for the same, i.e. working with SQL commands, in plus in MySQL Shell we can use JavaScript and Python scripts. 


Click next there is:

MySQL installation


Then click Execute:

MySQL installation

the install process start. 


MySQL installation

After install complete click Next


MySQL configuration process

It will follow configuration process.

MySQL configuration


Click Next

mySQL configuration-11

In this screen we can choose what king of server (computer) we will use, depending by the system resources (in special by RAM memory). As we see there are three choices: 

  • Development Computer
  • Server Computer
  • Dedicated Computer

We will choose Server Computer.


In the next step we configure server connectivity.

MySQL configuration

MySQL server as most database servers support three kind of 

connectivity: 

  • TCP/IP
  • Named Pipe, this is a bidirectional IPC (interprocess communication) usual on Windows.
  • Shared Memory, this kind of connection use a shared memory like a communication chanel by which client and server can communicate.

We choos TCP/IP like connectivity, this is reliable. 3306 is the usual TCP/IP port which is used most of the cases. 

There is also X protocol port 33060. A session object use this protocol to permit to run operation on the connected server. 


Click Next permit to choose authentication method.

MySQL configuration

We choose strong password encryption. 

Click Next.


mySQL configuration-root account password

In this screen we set root account password (remember it or note it). root user is the user with full privileges on server. In this screen using "Add User" account we can create new accounts. 

Click Next. 

MySQL configure windows service


MySQL configuring windows service

Here we set MySQL to run as a Windows Service (option valid as we install on windows). Running as a services is useful due easy procedure to start/stop service. 

We choose "Standard System Account" for run MySQL Service under a system account, which is more easy and safe. 

Click Next.


mySQL configuration-server files permission-16

In "Server File Permissions" we choose "Yes, grant full access...", usual this is for easy configuration, but sometime is more suitable second option where we can review and decide which privileges to grant.

Click Next.


mySQL configuration-apply-17

In "Apply Configuration" screen are listed all configuration steps 

that will be applied. Click Execute to apply those.

Click Execute.


MySQL configuration Finish.

After configuration is successful click Finish.


MySQL configuring sample.

Click Next to start to configure "Samples and Examples".


MySQL configuring samples

In this screen enter root password to connect to MySQL Server for configuring examples, then click Next.


MySQL configuring samples, connection to server successful.

In this screen is displayed that connection to MySQL server is successful.

Click Next.


MySQL Configuring samples.

This screen show configuration steps for Samples and Examples.

Click Next.


MySQL configuring samples.

Configuration for Samples and Examples is applied succesfully. Click Finish.


MySQL configuration.

Click Next.


MySQL configuration.

Instalation is complete. In this screen we can choose to start MySQL Workbench and/or MySQL Shell.

Click Finish.


MySQL Shell

This is how MySQL Shell looks.


MySQL Workbench.

This is MySQL Workbench.

Pyton OOP Tutorial – 3. Methods overriding

Derived classes allow code reuse this make code more easy to mantain and help in avoiding codding errors. However in derived class appear often casses when inherited method from parrent class isn't appropriate. 

For example let's presume we have an Employee class which have 3 attributes name, salary, phone and a method printEmployee which will display employee name and phone.

We derive from this a class Freelancer which have in plus atttribute domain. We need that for freelacer, printEmployee method to print name, phone and in plus domain. In this case printEmployee from base class is not apropriate and we need to extend it. Below is sample code:

class Employee:

   def __init__(self,nameValue, salaryValue, phoneValue):

      self.name=nameValue

      self.salary=salaryValue

      self.phone=phoneValue

   def getName(self):

      return self.name

   def getSalary(self):

      return self.salary

   def printEmployee(self):

       print(f"Employee: {self.name} have phone {self.phone}")


class Freelancer(Employee):

   def __init__(self,nameValue, salaryValue, phoneValue, domainValue):

      super().__init__(nameValue, salaryValue, phoneValue)

      self.domain=domainValue

   def printEmployee(self):

      print(f"Freelancer: {self.name} have phone {self.phone} and works in domain {self.domain}")


#create Employee object and use it printEmployee

emp1=Employee('Jd',4000,'555-342345')

emp1.printEmployee()

#create Freelancer object and use it overriding printEmployee method

fr1=Freelancer("TomH", 4200,'555-346534', 'Graphic design')

fr1.printEmployee()


#output:

Employee: Jd have phone 555-342345

Freelancer: TomH have phone 555-346534 and works in domain Graphic design


  • Observe in sample code that printEmployee method is implemented again (is overwritted) in Freelancer derived class. 
  • When we use printEmployee with a base class object, it will use method from base class see emp1.printEmployee() which will print "Employee: Jd have phone 555-342345".
  • When we use printEmployee with derived class object fr1, see fr1.printEmployee() it will check first in derived class if printEmployee is overriding and if yes, it will use it. Output of fr1.printEmployee() will be "Freelancer: TomH have phone 555-346534 and works in domain Graphic design".
  • Observation: If in derived class method is not override, then method from parent class will be used. 

Python OOP Tutorial – 2. Inheritance

By inheritance having already a class we can define a derived class from it, which 

will have all methods and attributes of the initial class, and in plus new methods and attributes.

The class from which we will define other classes is named base class, super class or parent class. 

New class defined using inheritance is named derived class, subclass or child class.

Using inheritance code is simplified and reuse code fragments (using derived class 

we can create new objects, for which we don't need to write code for attributes 

and methods from base class). We write code only for aditional attributes and methods from 

derived class.

Lets take an example of a company in which generic are working employes, but those can be 

regular employees, students, managers, contributors even freelancers. So we can define a base class 

named Employee which will contain a common set of attributes and methods that are for all mettioned prior. 

Then we can derive from base class Employee, classes named RegularEmployee, Student, Manager, Contributor, Freelancer 

Here is the code for base class Employee: 

class Employee:

def __init__(self, name, phone, departament):

self.name = name

self.phone = phone

self.departament = departament


def printemp(self):

print(self.name, self.phone, self.departament)


jd=Employee("John", "021111111", "IT")

jd.printemp()

print(jd.name)


#Output:

John Doe 021111111 IT

John Doe

We can create a class that inherit Employee and which have in plus attribute trainingStage which value show that employee is student 

Here is code with added derived class: 

class Employee:

def __init__(self, name, phone, departament):

self.name = name

self.phone = phone

self.departament = departament


def printemp(self):

print(self.name, self.phone, self.departament)


#inheritance

class Student(Employee):

trainingStage='undergraduate student'


jt=Student("John Trevor", "02122222", "Sales")

jt.printemp()

print(jt.trainingStage)

print(jt.name)


#output: 

John Trevor 02122222 Sales

student

John Trevor

We see inherited class Student have like "argument" initial or base class Employee

means general rule is 

class DerivedClass(BaseClass1, BaseClass2):

    <statement>

    .

    .

There is BaseClass1, BaseClass2, ... i.e inherited class can inherit from many base classes.

In code from above "jt" is a Student object. Class Student don't contain anything about attribute name, but 

because Student inherit Employee class, which have attribute name, then print(jt.name) , i.e. jt.name make sense, 

it will print name attribute from base class. When we try to access an attribute from inherited class, if attribute 

is in inherited class definition, it will be used, otherwhise it is used attribute from base class. Similar 

principle apply from methods. First python interpretor looks for method in inherited class, then if it not 

find it, then will check in base class. 

Python OOP Tutorial – 1. Objects in OOP

Initially it was procedural programing, which just uses methods or functions that do specific tasks. In procedural programing program logic flow linear, from start to end, sometime there point from functions that go to the program end. When programs become complex and there are many relationships between components working and maintaining procedural programs become difficult. From that reason appear object-oriented programing.

OOP is necessary especially when code becomes too complex, the code logic becomes too bushy. If we need to write a program for a car, imagine this have a logic for maintaining direction, for engine use, for lights, etc.  When writing programs for complex systems the solution is to identify entities and define classes for them. For each entity we have attributes and for those we use in classes variables. Each entity has specific functionalities and those correspond in classes to methods or functions. That is in simple mode OOP idea, obviously things are more complex, OOP means more like constructors, inheritance, interfaces, etc. We will discuss those later during tutorial.  Click here  for an exhaustive description of OOP. 

Let's take in this tutorial an example related to horticulture plants. What are some attributes of those plants? Some attributes are: lifetime, biological characteristics, color, type of seed, type of root, etc. What are some methods? Let's put here: germination, greeding, pollination, fruit ripening. The class is the blueprint that model OOP paradigm. First, we need to define the class. Then generate based on that many more objects, "instantiating" that class.


Simple example of class definition in python:

class Plant:

    def __init__(self, lifetime, biological_characteristic, fruit_weight):

        self.lifetime = lifetime

        self.biological_characteristic = biological_characteristic

        self.fruit_weight = fruit_weight

    def printplant(self):

        print(self.lifetime, self.biological_characteristic, self.fruit_weight)



mybrocolly = Plant("biennial", "vegetable", 250)

apple1 = Plant("perennial", "tree", 70)


print("Brocolly is a " + mybrocolly.lifetime + " plant")

print("Apple is a " + apple1.biological_characteristic)

mybrocolly.printplant()


#output 

Brocolly is a biennial plant

Apple is a tree

biennial vegetable 250


Explanation about above: 


The class name is Plant. It begin with capital letter ("P"). If class name is composed from multiple words, each first letter of the words should be in capital for example if we desire to name class "plantblueprint" correct name should be "PlantBlueprint", this  notation is known as "Pascal case" Class has three attributes: lifetime, biological_characteristic and fruit_weight.

__init__ is a special class method, the class constructor, inside it we initialize class attributes. After class definition we create two objects: 

mybrocolly using  line -> mybrocolly=Plant("biennial", "vegetable", 250) 

apple1 using line -> apple1=Plant("perennial", "tree", 70) 

In both cases mybrocolly and apple1 are objects and are created from the same "blueprint", class Plant

Observation: fruit_weight is in grams


Now some explanation about how __init__ (in some sources named constructor) works. When we run mybrocolly=Plant("biennial", "vegetable", 250)  constructor __init__ is appealed and it initialize object attributes, there will be: 

lifetime="biennial" which is realized by self.lifetime = lifetime constructor instruction 

biological_characteristic="vegetable" which is realized by  self.biological_characteristic = biological_characteristic

fruit_weight = 250 which is realized by  self.fruit_weight = fruit_weight


To access lifetime attribute of the mybrocolly object we used mybrocolly.lifetime, means in general to access atribute we 

use "objectname.attributename". Similar to acccess apple1 biological_characteristic attribute we used apple1.biological_characteristic.