Removing the last commit

Reverting back from a wrong commit

Once you made a wrong commit to your project, generally you would wanna perform one among these two things:

  • Revert the full commit

  • Delete the last commit or last to last commit, …

Revert the full commit

$ git revert 76eb9225c593b576d683b2453b05ad3b45c82ae

Where 76eb9225c593b576d683b2453b05ad3b45c82ae is the commit_id.

Delete the last commit

Let’s say we have a remote origin with branch master that currently points to commit 76eb9225c593b576d683b2453b05ad3b45c82ae. We want to remove the top commit i.e. we want to force the master branch of the origin remote repository to the parent of 76eb9225c593b576d683b2453b05ad3b45c82ae:

$ git push origin +76eb9225c593b576d683b2453b05ad3b45c82ae^:master

git interprets x^ as the parent of x and + as a forced non-fastforward push.

Thank you 👏

Crypt-git releases

crypt-git NPM version Build Status Dependency Status Coverage percentage

Got some important files which you don’t want to share publicly but still want to use github as VCS for your softwares. Crypt-git can help you.

crypt-git is a command line utility written in node.js which enables to encrypt important files when you push them on GitHub repo and decrypt then when you want to work locally on your system. Doing this is very very simple with ‘crypt-git’.

Installation

Install the module globally:

$ npm install -g crypt-git

Documentation

You just need to maintain a file .cryptfiles where you need to specify the file name(s) which you want to encrypt.

create .cryptfiles file:

touch .cryptfiles

edit .cryptfiles file

vim .cryptfiles

See an example here, this encrypts all the files named amit.txt in the repo.

To push:

$ cg push <commit message>
  • <commit message> is optional.

The above command is equivalent to doing these operations:

  • git add -A
  • git commit -m'your message'
  • git push -u origin master

Now all your important files mentioned in .cryptfiles file are pushed on your repository in encrypted (and compressed) form.

To decrypt:

When you want to work locally with your repository (without any encrypted file) then all you need is:

cg decrypt

NOTE: cg is abbreviation for crypt-git

When you perform cg decrypt, the encrypted file gets decrypted on your local machine.

Cool right?

Usage

$ cg push <commit message> // to push with the encrypted content.

cg decrypt // to decrypt the encrypted files

To know more read this.

NOTE:

Nothing important here that you don’t already know.

About branches

  • The supreme branch creates different .iv file for each encryption.

  • The master branch has static .iv file which gets created once (for the first time).

Release improvements

first release (v1.0.0)

  • It works fine for all cases except one case which you may need to handle properly.
  • If you perform two cg push operations one after the other without making any changes then the content of .iv file would get changed which will result in improper decryption thus you may face problem in decompression.
  • If you ever encounter any such problem just re-clone the project and do cg pull. Things will be fine.

Olympian release (v1.5.0)

  • This release takes care of commit history, because now every push doesn’t create a new encryption pattern into the file, So all the files doesn’t gets changes. This doesn’t make the commit history improper. To know more about this release see this

Sovereign release (v1.6.0)

  • The command cg pull is replaced with cg decrypt.
  • In this release git pull is not being performed because it is not required. The decryption process is done using the .iv file, which is available locally (so why to fetch again?), in case the file is deleted somehow, the user is asked to clone the repo and try decrypting again.

Chief release

  • Yet to come.
  • Major changes (TODO): 1) Ability to perform encryption of files with match of the regular expressions (this will help encryption of multiple files with same extension and irrespective of their names). 2) The .cryptfiles can take several lines of input and the each file or file path will get encrypted.

License

Apache-2.0 © Amit Upadhyay

Thank you 🎂 👏

Become modern with Java 8

Do you still have a habit of writing the Java programs in old fashion? It’s okay if you have, but I would suggest you become modern with Java8. You must be knowing that Java8 came with the concept of lambdas and stream APIs and these things have been introduced long before.

Why prefer lambdas?

Lambdas let us write code in more readable and concise way. With the use of lambdas, we avoid writing Anonymous classes. Now as you know each anonymous class will result in the formation of a .class file which will result in the increase of zar file(built project). So if you have 10 anonymous classes that are 10 more classes in the final jar.

In Java 1.7 a new JVM Opcode was released named invokedynamic and Java 8 Lambda uses this. Java 8 lambda uses invokedynamic to call lambdas thus if you have 10 lambdas it will not result in any anonymous classes.

Lets consider an example app where you have a list of people and you want to:

  • sort according to last name.
  • print them.
  • print people who have last name beginning with P.

Programming:

  • We need to create a blueprint of Person.
public class Person {

	private String firstName, lastName;
	int age;
	public Person(String firstName, String lastName, int age) {
		super();
		this.firstName = firstName;
		this.lastName = lastName;
		this.age = age;
	}
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [firstName=" + firstName + ", lastName=" + lastName + ", age=" + age + "]";
	}
}
  • Now as you know, we have to print the names according to the conditions and the conditions might be different, thus I need to create a contract (a common understanding, i.e. an interface).
public interface Condition {
	boolean test(Person p); // `p` is the person on which the particular condition will be applied.
}
  • Now a old fashioned Java programmer would like the code something like:
public class TraditionalWay {

	public static void main(String[] args) {
		
		java.util.List<Person> list = java.util.Arrays.asList(
				new Person("Amit", "Upadhyay", 20),
				new Person("Katrina", "Kaif", 21),
				new Person("Deepika", "Padukone", 22),
				new Person("Naina", "Bhatiya", 19),
				new Person("Sonal", "Peru", 19)
				);
		
		// step1: sort according to last name
		java.util.Collections.sort(list, new java.util.Comparator<Person>() {

					@Override
					public int compare(Person o1, Person o2) {
						
						return o1.getLastName().compareTo(o2.getLastName());
					}
		});
		
		// step2: print them
		System.out.println("Printing all names");
		System.out.println();
		printLists(list);

		// step3: print people who have last name beginning with P
		System.out.println();
		System.out.println("Printing names whose first character of last name is P");
		System.out.println();
		printConditionally(list, new Condition() {
			@Override
			public boolean test(Person p)
			{
				return p.getLastName().startsWith("P");
			}
		});
	}

	private static void printConditionally(java.util.List<Person> list, Condition c) {
		
		for (Person p: list)
			if (c.test(p))
			{
				System.out.println(p);
			}
		
	}

	private static void printLists(java.util.List<Person> list) {

		for (Person p: list)
			System.out.println(p);// this will call the toString method defined in Person class.	
	}
}

The above code creates Anonymous class just to pass a behaviour. Lets see how a modern programmer would write the code:

public class Java8Way {

	public static void main(String[] args) {
		
		java.util.List<Person> list = java.util.Arrays.asList(
				new Person("Amit", "Upadhyay", 20),
				new Person("Katrina", "Kaif", 21),
				new Person("Deepika", "Padukone", 22),
				new Person("Naina", "Bhatiya", 19),
				new Person("Sonal", "Peru", 19)
				);
		
		// step1: sort according to last name
		java.util.Collections.sort(list, (Person o1, Person o2) -> o1.getLastName().compareTo(o2.getLastName()));
		
		// step2: print them
		System.out.println("Printing all names");
		System.out.println();
		printLists(list);

		// step3: print people who have last name beginning with P
		System.out.println();
		System.out.println("Printing names whose first character of last name is P");
		System.out.println();
		printConditionally(list, p -> p.getLastName().startsWith("P"));
	}

	private static void printConditionally(java.util.List<Person> list, Condition c) {
		for (Person p: list)
			if (c.test(p))
			{
				System.out.println(p);
			}
	}

	private static void printLists(java.util.List<Person> list) {
		for (Person p: list)
			System.out.println(p);// this will call the toString method defined in Person class.	
	}
}

In the code you can see the difference.

Thank you 👏

Painless threading [part 4]

Synchronizing multiple thread

We have created more than one thread know as multiple threading, but multiple threading has an issue which is :

When we start two or more threads within a program, there may be a situation when multiple threads try to access the same resource. Whenever multiple threads are trying to access a same object, then we have to synchronize the thread such that unless the work of thread one gets completely executed for the object, no other thread should interfere its execution.

Synchronous – in sequence Asynchronous – parallel execution

NOTE : when we start two or more threads within a program there may be a situation when multiple threads try to access the same resource.

So there is need to synchronize the action of multiple threads and make sure that only one thread can access the resource at a given point of time.

Example of unsynchronized thread

class Account
{
  private int balance;
  
  public Account(int balance){ this.balance = balance; }
  
  public boolean isSufficient(int amt)
  {
    if (amt > balance)
    return false;
    else
    return true;
  }
  public void withdrawel(int amt)
  {
    balance -= amt;
    System.out.println("The money withdrawn is "+amt);
    System.out.println("Available balance is "+balance);
  }
}

class Customer implements Runnable
{
  private String name;
  private Account account;
  public Customer(Account account, String name)
  {
    this.name = name;
    this.account = account;
  }
  @Override
  public void run()
  {
    java.util.Scanner scanner = new java.util.Scanner(System.in);
    System.out.println("Enter amount to widhdraw : ");
    int amount = scanner.nextInt();
    if(account.isSufficient(amount))
    	account.withdrawel(amount);
    else
    	System.out.println("Insufficient balance");
    scanner.close();
  }
}


public class ExampleThreading {
  public static void main(String []args)
  {
    Account a = new Account(1000);
    Customer c1 = new Customer(a, "Amit"), c2 = new Customer(a, "Kat");
    
    Thread t1 = new Thread(c1), t2 = new Thread(c2);
    t1.start(); t2.start();
  }
}

Now lets see how to synchronize the threads.

We want to synchronize the code written inside the run() method. For this we write keyword synchronized(){}

NOTE: Syntax of synchronized may look like a method, but it is a keyword in java.

Argument inside the synchronized

Again, I choose wrong word because synchronized is not a function. But I need to write the “shared resource” (i.e. the object that is getting shared) inside the parenthesis. Now all the code that we want to synchronize will be written inside the curly braces.

Eg :

@Override
public void run()
{
  java.util.Scanner scanner = new java.util.Scanner(System.in);
  System.out.println("Enter amount to widhdraw : ");
  int amount = scanner.nextInt();
  synchronized (account)
  {
    if(account.isSufficient(amount))
    	account.withdrawel(amount);
    else
    	System.out.println("Insufficient balance");
  }
  scanner.close();
}

Thank you 🎂 👏

Painless threading [part 3]

Thread States

A java Thread is always in one of the several states which could be :

  1. New Thread
  2. Runnable
  3. Not Runnable
  4. Dead

So, there are 4 stages of thread in its whole life

1 st state : New Thread

A Thread is in this state when the instantiate of a Thread object gets created but doesn’t get started.] A Thread starts life in the Ready-to-run state. You can call only the start() or stop() method when the thread is in this state. Calling any method besides start() or stop() cause an IllegalThreadStateException ( A descendant class of RuntimeException)

2 nd state: Runnable

When the start() method is invoked on a new Thread() it gets to the runnable state r running state by calling run() method.

A Runnable thread may actually be running or may be waiting its turn to run.

3 rd state: Not Runnable

A Thread becomes Not Runnable when one of the following four events occurs:

  1. When sleep() method is invoked and it sleeps for a specified amount of time.
  2. When suspend() method is invoked.
  3. When wait() method is invoked and the thread waits for notification of few resource or waits for the completion of another thread or wait to acquire a lock of an object.
  4. Thread is blocking an I/O and waits for its completion.
  • sleep() is a method in Thread class and the argument of sleep is time in milliseconds.
  • suspend() method is not used these days.

Switching from Not Runnable to Runnalb state

  • If a thread has been put to sleep, then specified number of milliseconds must elapse ( or it must be interrupted).
  • If a thread has been suspended, then its resume() method must be invoked.
  • If a thread is waiting on a condition variable, whatever object owns the variable must relinquish it by calling either notify() or notifyAll().
  • If a thread is blocked or I/O, then I/O must be completed.

4 th state: Dead State

A thread enters this state when run() method has finished executing or when the stop() method is invoked or when any exception occurs. Once in this state, the thread can not ever run again.

Thread Priority

In java we can specify the priority of each thread relative to the other thread. Those threads having higher priority get grated access to the available resources. The thread priority is specified as a integer number.

By default there is some priority number set for a thread even if we don’t set any priority to a thread.

  • Thread priority is inherited

A java Thread inherits its priority from the thread that created it. By default our program runs into a thread whose priority number is 5. So each thread that we make is a child thread of parent thread. We can change the priority level if we want.

- Setting thread priority

We can modify a thread’s priority at any time after its creation using a method setPriority() and retrieve the thread priority by using a method getPriority().

The following static final integer constant are defined in the Thread class.

MIN_PRIORITY(0) : lowest priority
NORM_PRIORITY(5) : default priority
MAX_PRIORITY(10) : highest priority

Continue reading…

Painless threading [part 2]

Threading using Thread class

Here we will extend the Thread class. Again objective will be same :

  1. Creating Thread
  2. Attaching code to thread
  3. Executing Thread.

Here our class will inherit Thread class and override the run() method. The code snippet which we need to run of the Thread will be inside the run() method.

class A extends Thread
{
  public void run()
  {
  	function(){}
  }
}

The object of class A is also a Thread. So to create a new Thread we can write:

A obj = new A();

And now we can call the method of Thread class using object subclass of Thread class (i.e. object of A) So to start a Thread we can write :

obj.start();

This seems to be little bit simple, but there is difference in implementing Thread through Runnable interface and extending Thread class.

Example :

class A extends Thread
{
  @Override
  public void run()
  {
    for(int i = 1; i <= 10; ++i)
    {
    	System.out.println("Thread A "+i);
    }
  }
}

class B extends Thread
{
  @Override
  public void run()
  {
    for (int i = 1; i <= 10; ++i)
    {
    	System.out.println("Thread B "+i);
    }
  }
}


public class ExampleThreading {
  public static void main(String arp[])
  {
    A t1 = new A();
    B t2 = new B();
    
    t1.start();
    t2.start();
  }
}

Difference between implementing Runnable and extending Thread

Implementing Runnable to use Threading is better because in Java we don’t have multiple inheritance, so here as Thread is parent class of A, so it is not possible to have any other parent of A where as if we use Runnable interface then we can even have a parent of class A (other than the Thread class).

Continue reading…

Painless threading [part 1]

Thread – is an independent path of execution within a program. Many threads can run concurrently within a program and that way we say that multithreading refers to two or more task executing concurrently within a single program.

Thread class (java.lang.Thread)

Every Thread in java is created and controlled by the java.lang.Thread class. Whenever we create an object of Thread class then we say that we have created a Thread. Suppose that I have created 3 objects of Thread class t1, t2, t3 then we can say that we have created 3 threads. The important thing is to assign code to these threads, i.e. the codes which will get executed by these threads.

Before learning how to attach segment/snippet of code with a thread we will see way to create a Thread.

Benefits of creating Thread

Normally program gets executed sequentially, so after execution of first statement the second statement will get executed and so on. Now if the first statement and second statement are independent from each other then we can even run them parallel. This will save the time in execution of the program.

Creating Thread

There are two ways to create Thread in java

  • Implement the Runnable interface. (java.lang.Runnable),
  • By extending the Thread class (java.lang.Thread).

Steps involved to implement the concept of Thread

  • Create the object of Thread class.
  • Attach the segment of code with the object of Thread class which should run on execution of the Thread.

NOTE: We use multithreading for the concurrent execution of segments which are totally independent from each other.😄

Threads using Runnable Interface Our objective –

  • Create Thread
  • Attach code to Thread
  • Executing Thread

a) Create Thread

Thread t1 = new Thread(..); // .. represent arguments
Thread t2 = new Thread(..); // .. represent arguments

Now the process of creation of thread is done, next objective is to attach the code snippet to the Thread.

b) Attaching code

For this we make a class:

Example:

class A
{
	function(){}
}

Suppose that I want the code inside function() method to get attached with the Thread. For this we need to create object of class A and then pass that object in the constructor of Thread class which create the Thread.

Now the question is Since the Thread class is already predefined, so what type of argument does the constructor of Thread class takes?

One thing is clear that we need to pass the object of class A in the constructor of Thread class but the class A has been created now in our program. And passing the reference of class A as argument in constructor of Thread may result in type mismatching.

Now for this reason we use interface. We have Runnable interface (a predefined interface). There is only one method declared inside Runnable interface and that is run() method.

Now class A will implement the Runnable interface so it is important to override the run() method.

So we have to write the class A as :

class A
{
  public void run()
  {
  	function(){}
  }
}

or we can just replace the body of method function() with the body of run() function.

Benefits of implementing Runnable interface

Since A implements, the Runnable interface, so any reference variable of Runnable interface can be kept in the reference variable of class A (i.e. object of class A).

i.e.

 Runnable r1 = new A();

Since Runnable is predefined so we can say that constructor of Thread class can receive a Runnable type of value. i.e. we can pass the object which has implemented the Runnable interface into the constructor of Thread class.

So we can say that one of the constructor of Thread class could be something like :

Thread (Runnable r1)
{
}

c) To execute Thread

t1.start(); // this will start execution of Thread t1

Example Program :


class A implements Runnable
{
  @Override
  public void run()
  {
    for(int i = 1; i <= 10; ++i)
    {
    	System.out.println("Thread A "+i);
    }
  }
}
class B implements Runnable
{
  @Override
  public void run()
  {
    for (int i = 1; i <= 10; ++i)
    {
    	System.out.println("Thread B "+i);
    }
  }
}

public class ExampleThreading {
  public static void main(String arp[])
  {
    Thread t1 = new Thread(new A());
    Thread t2 = new Thread(new B());
    
    t1.start();
    t2.start();
  }
}

Sample output:

Thread A 1
Thread A 2
Thread B 1
Thread B 2
Thread B 3
Thread B 4
Thread B 5
Thread B 6
Thread B 7
Thread A 3
Thread A 4
Thread A 5
Thread A 6
Thread A 7
Thread A 8
Thread A 9
Thread A 10
Thread B 8
Thread B 9
Thread B 10

Continue reading…

An editorial on finding the prime number with least time complexity

  • The algorithm can be improved further by observing that all primes are of the form 6m ± 1, with the exception of 2 and 3.
  • This is because all integers can be expressed as (6m + i) for some integer k and for i = −1, 0, 1, 2, 3, or 4; 2 divides (6m + 0), (6m + 2), (6m + 4); and 3 divides (6m + 3).
  • So a more efficient method is to test if n is divisible by 2 or 3, then to check through all the numbers of form 6m ± 1 ≤ √n(sqrt(n)).
  • This is 3 times as fast as testing all m up to √n.
int CheckPrime(unsigned int number) {
    if (number <= 3 && number > 1) 
        return 1;            // as 2 and 3 are prime
    else if (number%2==0 || number%3==0) 
        return 0;     // check if number is divisible by 2 or 3
    else {
        unsigned int i;
        for (i=5; i*i<=number; i+=6) {
            if (number % i == 0 || number%(i + 2) == 0) 
                return 0;
        }
        return 1; 
    }
}
  • This code is written in C, in java we don’t have unsigned keyword(however in java 8 it is included).

Thank you 🎂 👏

Introduction to classes and objects

Classes

It is basically a blueprint to create objects. An object is a basic key concept of OOP but classes provide an ability to generalize similar type of objects.

Object

Every object is characterised by:

  • Identity: This is the name that identifies an object.

  • Properties: These are the features or attributes of the object.

  • Behaviour: The behaviour of an object signifies what all functions an object can perform.

Defining Classes

It encapsulates data and its associated functions. To define a class in Python, we need to just define the class and start coding. A Python class starts with the reserved word class, followed by the class name and a colon(:).

Everything in a class is indented after the colon, just like the code within a function, if statement or for loop. The first thing not indented is not part of the class definition. A class may contain attributes which can be data members or/and member functions i.e. methods. In fact the word attribute is used for any name following a dot. Let us take the example of class Test:

class Test:
	var = 50
	marks = 10
	def display():
		print var

In the above class definition, marks, var, display(), all are attributes of the class Test and also of all its objects. Similarly when we import modules, in the expression module1.fuctionname, module1 is a module object and function name is a method but also referred to as an attribute of module1. The module’s attributes and the global names are defined in the same namespace. Class definitions, like function definitions using def statements must be given before they are referenced for use. When a class definition is entered a new namespace is created and then used as local scope. Hence all assignments to the local variables are attached with this namespace.

Attributes of a class may be read-only or writable. In the latter case, assignment to attributes is possible. That means the following statement is valid:

test1.marks=10

Writable attributes may also be deleted using the del statement. For example:

del test1.marks

The above statement will remove the attribute marks from the object named test1.In fact the del statement removes the binding of the attribute (marks) from the namespace (test1) referenced by the class’s local scope. When a class definition is left normally (via the end), a class object is created. This is basically a wrapper around the contents of the namespace created by the class definition.

Note that calling a method on an object can also change the object. This implies that an object is mutable. A function can modify an outer mutable object by calling a method on it.

Consider the example below:

x = [10]


def list_ex():
    x.append(20)


def add_list():
    x = [30, 40]
    x.append(50)


print x
list_ex()
print x
add_list()
print x

The above example prints

[10]
[10, 20]
[10, 20]

The list_ex() calls the append method of the global x, whereas the add_list(), x refers to a local x.

Also data attributes override method attributes with the same name. That means if the data attribute of the class and the method attribute are in same scope, then the data attribute will be given higher priority. So to avoid accidental name conflicts.

If the class does not contain any statements i.e. it is a class without any attributes or methods , then a keyword pass is given within the body of the class as shown below :

class mobile:
	pass

In the above example pass is a keyword. Giving pass in the class definition means that the class doesn’t define any methods or attributes. But since there needs to be something in the definition, so you use pass. It’s a statement that does nothing.

Constructors in Python (Using init)

In python, the built in method __init__ is a sort of constructor. Notice the double underscores both in the beginning and end of init. In fact it is the first method defined for the class and is the first piece of code executed in a newly created instance of the class. But still it should also be remembered that the object has already been constructed by the time __init__ is called, and you already have a valid reference to the new instance of the class through the first argument, self of the __init__ method.

Consider the following example:

class Initialize:
	int var
	def __init__(self, var=10): #double underscore before and after init
		Initialize.var=var
	def display():
	print var

__init__ method can take any number of arguments, and just like functions, the arguments can be defined with default values, making them optional to the caller. Initial values for attributes can be passed as arguments and associated to attributes. A good practice is to assign them default values, even None. In this case, var has a default value of 10. After the class definition, object.__init__(self[, ...]) is called when the instance is created. The arguments are those passed to the class constructor expression. This means the statements given below will give the output 20.

P = Initialize(20)
P.display()

Also note that if no argument was passed while creating the object, then the __init__ would have taken the default value of var and the output would have been 10. In Python, the first argument of every class method, including __init__, is always a reference to the current instance of the class and by convention, this argument is always named self. In case of __init__, self refers to the newly created object or the instance whose method was called. Note that the __init__ method never returns a value.

Importance of self

Class methods have only one specific difference from ordinary functions - they must have an extra argument in the beginning of the parameter list. This particular argument is self which is used for referring to the instance. But you need not give any value for this parameter when you call the method. Python provides it automatically. self is not a reserved word in Python but just a strong naming convention and it is always convenient to use conventional names as it makes the program more readable. So while defining your class methods, you must explicitly list self as the first argument for each method, including __init__.

To understand why you don’t need to give any value for self during the method call, consider an example. Say you have a class called My_Photo and an instance of this class called My_Object. When you call a method of this object as My_Object.method(arg1, arg2), this is automatically converted by Python into My_Photo.method(My_Object, arg1, arg2). This feature makes self special and it also implies that if you have a method which takes no arguments, then you still have to define the method to have a self argument.

Self is an instance identificator and is required so that the statements within the methods can have automatic access to the current instance attributes. Here is the example showing a class definition using __init__ and self.

class Mobile:

	price = 0
	model = "Null"

	def __init__(self, price, model = None):
		self.price=price
		self.model="Nokia Lumia 720"

	def displaydata(self):
	print self. price, self. model

In the above example:

  • The variables price and model are the class variables whose value would be shared among all instances of this class. This can be accessed as Mobile.price, Mobile.model from inside the class or outside the class.

  • The first method __init__() is a special method, which is called class constructor or initialization method that Python calls when you create a new instance of this class.

  • You declare other class methods like normal functions with the exception that the first argument to each method is self. While giving a call to the method, the instance name is automatically taken as the first argument for self.

If after the given class definition of class Mobile, the following statements are executed

M= Mobile(1000, 'Samsung')
M.displaydata()

the output is

1000 Samsung

Class instances (Objects)

In fact after the class definition is made, a class instance is created automatically once the definition is left normally i.e. the indentation of statements is removed and the class object is called. All the instances created with a given class will have the same structure and behaviour. They will only differ regarding their state, i.e regarding the value of their attributes.

Classes and instances have their own namespaces, that is accessible with the dot (‘.’) operator. These namespaces are implemented by dictionaries, one for each instance, and one for the class. A class object is bound to the class name given in the class definition header. A class object can be used in two ways - by Instantiation and attribute references.

1. Instantiation: Creating instance objects

To create instances of a class, you call the class using class name and pass in whatever arguments its __init__ method accepts.

Test = T(1,100)

In the above example T is the instance of class Test.

2. Attribute Reference: Accessing attributes of a class

Object Name. Attribute Name

As discussed before all the names that were given during the class definition and hence were in the class’s namespace are valid attribute names.

Example:

test.display()
unit_test.display()
print "Marks =", test. marks

The search for the referenced attribute is done in the following sequence:

a) A class instance has a namespace implemented as a dictionary which is the first place in which attribute references are searched.

b) When an attribute is not found there, and the instance’s class has an attribute by that name, the search continues with the class attributes.

c) If no class attribute is found, the object’s __getattr__() method is called to satisfy the lookup. You will study about this method later in the chapter.

Attribute assignments and deletions update the instance’s dictionary, never a class’s dictionary. If the class has a __setattr__() or __delattr__() method, this is called instead of updating the instance dictionary directly. You will learn about these methods later in this chapter.

Class Atttributes v/s Instance Attributes

Attributes can be classified into - Class Attributes and Instance attributes.

Class Attributes

These belong to the class itself. These attributes will be shared by all the instances. Such attributes are defined in the class body part, usually at the top, for legibility. Consider the following example:

Example:

class Health_profile:
		...
	weight = 89
	blood_group= 'B+'
	...

# To access this attribute, you use the dot notation:
>>> Health_profile.weight
89
>>> Health_profile.blood_group
B+

Instances attributes

As we have learnt, a class may define attributes for its instances. These are called instance attributes and they belong to each instance/object of a class. For example, for the class Health_profile given above, let H1 be an instance. So, the attributes of H1, such as the weight, are directly available through the dot operator:

>>>H1.weight
89

The dictionary for the instance attributes is also accessible by its __dict__ variable about which you will learn in the next section. To list the attributes of an instance, we have two functions:

i) vars() : This function displays the attributes of the instance in the form of a dictionary. Consider the following example:

>>>vars(H1)
{'weight': '89', 'blood group': 'B+'}

ii) dir(): This function lists more attributes than vars()because it is not limited to the dictionary of instance. It also displays the class attributes.

For example

>>>dir(H1)
['__doc__', '__init__', '__module__', 'weight', 'blood_group',]

You can add, remove or modify attributes to an instance that were not defined by the class, such as the height in the following:

>>> H1.height = 197 # adds 'height' as attribute
>>>  vars(H1)
{'weight': '89', 'blood group': 'B+',height='197'}
>>>H1. height=180 #modifies the value of height
>>> vars(H1)
{'weight': '89', 'blood group': 'B+',height='180'}
>>> del H1.height #deleted the attribute height
>>> vars(H1)
{'weight': '89', 'blood group'}

Here it should always be remembered that this feature of adding and deleting attributes should be used carefully, since by doing this, you start to have instances that have different behaviour than that is specified in the class.

Adding methods dynamically

As you can add, modify and delete the attributes of a class dynamically i.e. at run time, similarly, you can add methods dynamically to an object or class. Consider the code given below:

pyclass Health_profile:
		...
		weight = 89
		blood_group= 'B+'

	def play():
		print " Come on lets play"

	H=Health_profile()
	H.play=play()
	H.play()

In the above example, play is just a function which does not receive self. There is no way by which H can know that play is a method. If you need self, you have to create a method and then bind it to the object. For this you have to import MethodType from types module as shown in the example below:

from types import MethodType
class Health_profile(object):
		weight = 89
		blood_group= 'B+'

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

	def play():
		print " Come on lets play", self.name

	H=Health_profile("Shalini")
	H.play=MethodType(play,H)
	H.play()

In the above code, the built in function MethodType from the types module takes two arguments - the name of the function which has to be bound dynamically and the instance with which it has to bind the function. In the above example the play method will be bound only with the instance, H. No other instances of the class Health_profile will have play method. If we want the other instances also to have play method, then we have to add the method to the class and for that we make use of self as shown in the example below:

class Health_profile(object):
		weight = 89
		blood_group= 'B+'

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

	def play(self):
		print " Come on lets play", self.name

	Health_profile.play=play()
	H1=Health_profile("Shalini")
	H1.play()
	H2=Health_profile("Ritu")
	H2.play()

In the above example, note that no method is created with types.MethodType. This is because all functions in the body of the class will become methods and receive self unless you make it a static method.

Accessing Attributes and methods

Attributes of a class can also be accessed using the following built in methods / functions:

  • getattr(obj, name[, default]): This function is used to access the attribute of object.It is called when an attribute lookup has not found the referenced attribute in the class. The built in method for the same is object. getattr(self , name)which is called automatically if the referenced attribute is not found.

For example:

getattr(H1,weight)
# Built in method for the same will be
H1.__getattr__(self,weight)

The above statement returns the value of the weight attribute otherwise raises an AttributeError exception. Note that if the attribute is found through the normal mechanism, __getattr__() is not called.

  • hasattr (obj,name): It is used to check if an attribute exists or not.

For example:

hasattr(H1,weight) # will return a True if 'weight' attribute exists
  • setattr (obj, name, value): It is used to set an attribute. Alternatively object.__setattr__(self, name, value) built in method is called when an attribute assignment is attempted , where name is the name of the attribute and value is its value that is to be assigned. If an attribute does not exist, then it would be created.

For example:

setattr(H1,weight,90)
# The built in method for the same will be
H1.__setattr__(self,weight,90)
# Either of the above statements set the value of the attribute weight as 90.
  • delattr(obj, name): It is used to delete an attribute.The built in method for the same is object.__delattr__(self , name).

For example :

delattr(H1,weight) # deletes the attribute weight
# The built in method for the same will be
H1.__delattr__(self,weight)

Accessing Methods

When an instance attribute other than the data attribute is referenced, the corresponding class is searched. If it is a valid class attribute (a function object), a method is created by pointing to the instance object and the function object. When this method object is called with an argument list, a new argument list is constructed from the instance object and the argument list. The function object is then called with this new argument list. The methods of a class can be accessed in the same manner as the data attributes i.e.

ObjectName.Methodname

Now, putting all the concepts together, let us see the following example:

class Health_profile:
		weight=0
		blood_group='B+'

	def __init__(self,weight,blood_group):
		self.weight=weight
		self.blood_group=blood_group

	def display(self):
		print " Weight :" , self.weight
		print "Blood Group : " , self.blood_group

The following statement will create an object (instance) of class Health_profile

H2=Health_profile(61 ,'A+') # Assuming weight is 61 and blood group is A+

On executing the statement H1.display(), the output will be :

Weight :61
Blood Group :A+

A function object need not always be textually enclosed in the class. We can also assign a function object to a local variable in a class. For example

def test ( a ,b):
	return x+y


class myclass:
		F=test(10,20)

	def G(self):
		return F
	``` Using a function that is defined outside the class```

	H=G

In the above example F, G and H are all attributes of class myclass. They refer to the function objects and hence are all methods of instances of myclass.

Methods may also be referenced by global names in the same way as ordinary functions. The global scope associated with a method is the module containing its definition. Although global data in a method is rarely used, functions and modules imported into a global scope can be used by methods, functions and classes defined in it. Usually a class containing the method is itself defined in this global scope.

For example

class myclass:
	Yf=x.f()

	while true:
		printYf()

In the above example, you will notice that it is not necessary to call a method right away. x.f() is a method object and can be stored(in Yf) and called later (in the while loop). In case of methods, the object is passed as the first argument of the function. So even if no argument is given in the function call while it was defined in the function definition, no error is flashed. In the above example x.f() is exactly equivalent to myclass.f(x). So we can say that calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s object before the first argument.

Built in class attributes

Every Python class keeps the following built-in attributes and they can be accessed using dot operator like any other attribute:

i) __dict__ : It gives the dictionary containing the class’s namespace.

ii) __doc__ : It returns the class’s documentation string(also called docstring) and if no docstring is defined for a class this built in attribute returns None

iii) __name__: It gives the class name.

iv) __module__: It specifies the module name in which the class is defined. This attribute is called __main__ in interactive mode.

v) __bases__ : It gives a possibly empty tuple containing the base classes, in the order of their occurrence in the base class list. (You will learn about base classes in the next chapter on Inheritance)

For the previously defined class Test let’s try to access all the above built in attributes:

class Test:
'''A sample class to demonstrate built in attributes'''

		rollno=1
		marks=75


	def __init__(self,rollno,marks):
		self.rollno=rollno
		self.marks=marks

	def display(self):
		print " Roll No : " , self.rollno
		print "Marks : " , self.marks

	print "Test.__doc__:" , Test.__doc__
	print "Test.__name__:" , Test.__name__
	print "Test.__module__:" , Test.__module__
	print "Test.__bases__:" , Test.__bases__
	print "Test.__dict__:" , Test.__dict__

Using __del()__

This function is called when the instance is about to be destroyed. This is also called a destructor. It calls the method - object.__del__(self)

When __del()__ is invoked in response to the module being deleted (for example , when the execution of the program is done), the other global variables referenced by del() method may already have been deleted or must be in the process. Let us understand the concept through the class Test whose instance is T1.

Consider the following command is given

>>> del T1

The above command doesn’t directly call T1.__del__(). First the reference count is decremented for T1 by one and __del()__ is called only when T1’s reference count reaches zero i.e. when all the variables referenced by T1 have been deleted.

Using __str()__

It is a special function which returns the string representation of the objects. It calls the method object.__str__(self). If the class defines a __str__ method, Python will call it when you call the str() or use print statement. The str() built-in function, when used along with the print statement computes the informal string representation of an object. Consider the following example of the class Test defined above.

class Test:
		..........
		...........

	def __str__(self):
		return "Hello, How are you?"

Now give the following command on the Python interpreter:

>>> T=Test()
>>> print T
	Hello, How are you?

When you give the command to print T, Python calls str(T) to get the string representation of T. If the class of T has a __str__ method, str(T) becomes a call to T.__str__(). This returns the string to print.

Thank you 👏

Reverse string Python

str = ‘Amit Upadhyay’

Approach 1:

print str[::-1]

Approach 2:

"".join(reversed(str))

It requires calling a string method str.join on another called function, which canbe rather slow.

Approach 3:

def reverseString (str):
    newStr = ""
    index = len(str)

    while index:
        index -= 1
        newStr += str[index]
    return newStr;


print reverseString("Amit Upadhyay")

This is bad because strings are immutable. So every time you are appending a new character, which is creating a new string. So it is better to collect your substring in a list and join them later. This moves us to the approach 4.

Approach 4:

def reverseString (str):
    newList = []
    index = len(str)

    while index:
        index -= 1
        newList.append(str[index])
    return "".join(newList);


print reverseString("Amit Upadhyay")

Thank you 👏

Extended slices

This opeartor operates on all kind of sequences.

Suppose that you wanna extrace the elements of list that have even indices:

>>> L = range(10)
>>> L[::2]
[0, 2, 4, 6, 8]

-ve value also work to make a copy of the same list in reverse order.

>>> L = range(10)
>>> L[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

This also works for tupples and lists.

NOTE: There are some differences between assignments to extended and regular slices. Assignment can only be done in case of mutable sequences.

>>> a = range(3)
>>> a
[0, 1, 2]
>>> a[1:3] = [4, 5, 6]
>>>a
[0, 4, 5, 6]

Extended slice is not this flexible, when assigning to an extended slice, the list on the right hand side of the statement must contain the same number of items as the slice it is replacing.

>>> a = range(4)
>>> a
[0, 1, 3, 4]
>>> a[::2]
[0, 2]
>>> a[::2] = [0, -1]
>>> a
[0, 1, -1, 3]

Thank you 🎂 👏

Tuple in python

What is a Tuple?
A tuple is a sequence of values, which can be of any type and they are indexed by integer. Tuples are just like list, but we can’t change values of tuples in place. Thus tuples are immutable. The index value of tuple starts from 0.

A tuple consists of a number of values separated by commas.

For example:

>>> T=10, 20, 30, 40
>>> print T
(10, 20, 30, 40)

But in the result, same tuple is printed using parentheses. To create a tuple with single element, we have to use final comma. A value with in the parenthesis is not tuple.

Example:

>>> T=(10)
>>> type(T)
<type 'int'>

>>> t=10,
>>> print t
(10,)

>>> T=(10,20)
>>> type(T)
<type 'tuple'>

Example:

# Tuple with string values
>>> T=('sun','mon','tue')
>>> print T
('sun', 'mon', 'tue')

# Tuples with single character
>>> T=('P','Y','T','H','O','N')
>>> print T
('P', 'Y', 'T', 'H', 'O', 'N')

Tuple Creation

If we need to create a tuple with a single element, we need to include a final comma.

Example
>>> t=10,
>>> print t
(10,)

Another way of creating tuple is built-in function tuple().

Syntax:

T = tuple()

Example:

>>> T=tuple()
>>> print T
()

Add new element to Tuple

We can add new element to tuple using + operator.

Example:

>>> t=(10,20,30,40)
>>> t+(60,)
# this will not create modification of t.
(10, 20, 30, 40, 60)
>>> print t
(10, 20, 30, 40)
>>> t=t+(60,) # this will do modification of t.
>>> print t
(10, 20, 30, 40, 60)

Example

Write a program to input n numbers and store it in tuple.

Code

t=tuple()
n=input("Enter any number")
print " enter all numbers one after other"
for i in range(n):
	a=input("enter number")
	t=t+(a,)
print "output is"
print t

Another version of the above program:

t=tuple()
n=input("Enter any number")
print " enter all numbers one after other"

for i in range(n):
	a=input("enter number")
	t=t+(a,)

print "output is"
for i in range(n):
	print t[i]

We can also add new element to tuple by using list. For that we have to convert the tuple into a list first and then use append() function to add new elements to the list. After completing the addition, convert the list into tuple. Following example illustrates how to add new elements to tuple using a list.

>>> T=tuple() #create empty tuple
>>> print T
()
>>> l=list(T) #convert tuple
into list
>>> l.append(10) #Add new elements to list
>>> l.append(20)
>>> T=tuple(l)
#convert list into tuple
>>> print T
(10, 20)

Initializing tuple values:

>>> T=(0,)*10
>>> print T
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

Tuple Assignment

If we want to interchange (swap) any two variable values, we have to use temporary variable.

Example:

>>> A=10
>>> B=20
>>> print A,B
10 20
>>> T=A
>>> A=B
>>> B=T
>>> print A,B
20 10

But in python, tuple assignment is more elegant:

Example:

>>> T1=(10,20,30)
>>> T2=(100,200,300,400)
>>> print T1
(10, 20, 30)
>>> print T2
(100, 200, 300, 400)
>>> T1,T2=T2,T1
# swap T1 and T2
>>> print T1
(100, 200, 300, 400)
>>> print T2
(10, 20, 30)

The left side is a tuple of variables, while the right side is a tuple of expressions. Each value is assigned to its respective variable. All the expressions on the right side are evaluated before any of the assignments. The number of variables on the left and the number of values on the right have to be the same:

Example

>>> t1 = (10, 20, 30)
>>> t2 = (100, 200, 300)
>>> t3 = (1000, 2000, 3000)
>>> t1, t2 = t2, t1, t2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack

Here, two tuples are in the left side and three tuples are in right side. That is why, we get errors. Thus, it is required to have same number of tuples in both sides to get the correct result.

Example

>>> T1,T2,t3=t3,T1,T2
>>> print T1
(1000, 2000, 3000)
>>> print T2
(10, 20, 30)
>>> print t3
(100, 200, 300)

Tuple Slices

Slice operator works on Tuple also. This is used to display more than one selected value on the output screen. Slices are treated as boundaries and the result will contain all the elements between boundaries.

Syntax is:

Seq = T [start: stop: step]

Where start, stop & step all three are optional. If we omit first index, slice starts from 0. On omitting stop, slice will take it to end. Default value of step is 1.

Example

>>> T=(10,20,30,40,50)
>>> T1=T[2:4]
>>> print T1
(30, 40)

In the above example, starting position is 2 and ending position is 3 (i.e. 4-1), so the selected elements are 30 & 40.

>>> T[:]
(10, 20, 30, 40, 50) # Will produce a copy of the whole tuple.

>>> T[::2]
(10, 30, 50) # Will produce a Tuple with every alternate element.

>>> T[:3]
(10, 20, 30) # Will produce 0 to 2(3-1)

>>> T[2:]
(30, 40, 50) # Will produce from 2 to end.

Tuple Functions

cmp()

This is used to check whether the given tuples are same or not. If both are same, it will return zero, otherwise return 1 or -1. If the first tuple is big, then it will return 1, otherwise return -1.

Syntax:

cmp(t1,t2) # t1and t2 are tuples.

returns 0 or 1 or -1

Example

>>> T1=(10,20,30)
>>> T2=(100,200,300)
>>> T3=(10,20,30)
>>> cmp(T1,T2)
-1
>>> cmp(T1,T3)
0
>>> cmp(T2,T1)
1

len()

It returns the number of items in a tuple.

Syntax:

len(t) # t tuples

returns number of items in the tuple.

Example

>>> T2=(100,200,300,400,500)
>>> len(T2)
5

max()

It returns its largest item in the tuple.

Syntax:

max(t) # t tuples

returns maximum value among the given tuple.

Example

>>> T=(100,200,300,400,500)
>>> max(T)
500

min()

It returns its smallest item in the tuple.

Syntax:

min(t) #t tuples

returns minimum value among the given tuple.

Example

>>> T=(100,200,300,400,500)
>>> min(T)
100

tuple()

It is used to create empty tuple.

Syntax:

T=tuple() #t tuples

Create empty tuple.

Example

>>> t=tuple()
>>> print t
()

Thank you 👏

Dictionary in python

What is a dictonary?
A dictionary is like a list, but more in general. In a list, index value is an integer, while in a dictionary index value can be any other data type and are called keys.

The key will be used as a string as it is easy to recall. A dictionary is an extremely useful data storage construct for storing and retrieving all key value pairs, where each element is accessed (or indexed) by a unique key. For accessing an element of the list, indexing is used. However, dictionary keys are not in sequences and hence maintain no left-to right order.

Are the key always a string as we have in JSON key-value pair? Think about it.

What is a Key-value pair?

We can refer to a dictionary as a mapping between a set of indices (which are called keys) and a set of values. Each key maps a value. The association of a key and a value is called a key-value pair.

Syntax:

my_dict = {'key1': 'value1','key2': 'value2','key3': 'value3'...'keyn': 'valuen'}

Note: Dictionary is created by using curly brackets(ie. {}).

Example 1:

>>> A={1:"one",2:"two",3:"three"}
>>> print A
{1: 'one', 2: 'two', 3: 'three'}

In the above example, we have created a list that maps from numbers to English words, so the keys values are in numbers and values are in strings.

Example 2:

>>>computer={'input':'keybord','output':'mouse','language':'python','os':'windows-8',}
>>> print computer
{'input': 'keyboard', 'os': 'windows-8', 'language': 'python', 'output': 'mouse'}

In the above example, we have created a list that maps from computer related things with example, so here the keys and values are in strings. The order of the key-value pairs is not in same order (ie. input and output orders are not same). We can get different order of items in different computers. Thus, the order of items in a dictionary is unpredictable.

Example 3:

>>> D={'sun':'Sunday','mon':'Monday','tue':'Tuesday','wed':'Wednesday','thu':'Thursday','fri':'Friday','sat':'Saturday'}
>>> print D
{'wed': 'Wednesday', 'sun': 'Sunday', 'thu': 'Thursday', 'tue': 'Tuesday', 'mon':'Monday', 'fri': 'Friday', 'sat': 'Saturday'}

Why is dictionary un-ordered?

  • The order is not arbitrary, but depends on the insertion and deletion history of the dictionary or set, as well as on the specific Python implementation.

  • Sets are implemented as dictionaries with just keys and no values.

  • Keys are hashed, and hash values are assigned to slots in a dynamic table (it can grow or shrink based on needs). And that mapping process can lead to collisions, meaning that a key will have to be slotted in a next slot based on what is already there.

  • Listing the contents loops over the slots, and so keys are listed in the order they currently reside in the table.

  • Take the keys foo and bar, for example, and lets assume the table size is 8 slots. In Python 2.7, hash('foo') is -4177197833195190597, hash('bar') is 327024216814240868. Modulo 8, that means these two keys are slotted in slots 3 and 4 then:

>>> hash('foo')
-4177197833195190597
>>> hash('foo') % 8
3
>>> hash('bar')
327024216814240868
>>> hash('bar') % 8
4

This informs their listing order:

>>> {'bar': None, 'foo': None}
{'foo': None, 'bar': None}

All slots except 3 and 4 are empty, looping over the table first lists slot 3, then slot 4, so foo is listed before bar.

bar and baz, however, have hash values that are exactly 8 apart and thus map to the exact same slot, 4:

>>> hash('bar')
327024216814240868
>>> hash('baz')
327024216814240876
>>> hash('bar') % 8
4
>>> hash('baz') % 8
4

Their order now depends on which key was slotted first; the second key will have to be moved to a next slot:

>>> {'baz': None, 'bar': None}
{'bar': None, 'baz': None}
>>> {'bar': None, 'baz': None}
{'baz': None, 'bar': None}

The table order differs here, because one or the other key was slotted first. The technical name for the underlying structure used by CPython (the most commonly used Python implemenation) is a hash table, one that uses open addressing.


You should probably watch these videos about how CPython dict works


Note that as of Python 3.3, a random hash seed is used as well, making hash collisions unpredictable to prevent certain types of denial of service (where an attacker renders a Python server unresponsive by causing mass hash collisions). This means that the order of a given dictionary is then also dependent on the random hash seed for the current Python invocation.

Python 2.7 and newer also provides an OrderedDict class, a subclass of dict that adds an additional data structure to record key order. At the price of some speed and extra memory, this class remembers in what order you inserted keys; listing keys, values or items will then do so in that order. It uses a doubly-linked list stored in an additional dictionary to keep the order up-to-date efficiently.

Creation, initializing and accessing the elements in a Dictionary

The function dict() is used to create a new dictionary with no items. This function is called built-in function. We can also create dictionary using {}.

>>> D=dict()
>>> print D
{}

{} represents empty string. To add an item to the dictionary (empty string), we can use square brackets for accessing and initializing dictionary values.

Example:

>>> H=dict()
>>> H["one"]="keyboard"
>>> H["two"]="Mouse"
>>> H["three"]="printer"
>>> H["Four"]="scanner"
>>> print H
{'Four': 'scanner', 'three': 'printer', 'two': 'Mouse', 'one': 'keyboard'}

Traversing a dictionary

This can be done by using for-loop.

Example:

code

H={'Four': 'scanner', 'three': 'printer', 'two': 'Mouse', 'one': 'keyboard'}
for i in H:
print i,":", H[i]," ",

output:

Four: scanner
one: keyboard
three: printer
two: Mouse

As said previously, the order of items in a dictionary is unpredictable.

Creating, initializing values during run time (Dynamic allocation)

We can create a dictionary during run time also by using dict () function. This way of creation is called dynamic allocation. Because, during the run time, memory keys and values are added to the dictionary.

Write a program to input total number of sections and class teachers’ name in 11 th class and display all information on the output screen.

classxi=dict()
n=input("Enter total number of section in xi class")
i=1

while i<=n:
	a=raw_input("enter section")
	b=raw_input ("enter class teacher name")
	classxi[a]=b
	i=i+1


print "Class","\t","Section","\t","teacher name"
for i in classxi:
	print "XI","\t",i,"\t",classxi[i]

Appending values to the dictionary

We can add new elements to the existing dictionary, extend it with single pair of values or join two dictionaries into one. If we want to add only one element to the dictionary, then we should use the following method.

Syntax:

dictionary_name [key]=value

Example:

>>> a={"mon":"monday","tue":"tuesday","wed":"wednesday"}
>>> a["thu"]="thursday"
>>> print a
{'thu': 'thursday', 'wed': 'wednesday', 'mon': 'monday', 'tue': 'tuesday'}

Merging dictionaries: An update()

Two dictionaries can be merged in to one by using update() method. It merges the keys and values of one dictionary into another and overwrites values of the same key.

Syntax:

Dic_name1.update (dic_name2)

Using this dic_name2 is added with Dic_name1.

Example:

>>> d1={1:10,2:20,3:30}
>>> d2={4:40,5:50}
>>> d1.update(d2)
>>> print d1
{1: 10, 2: 20, 3: 30, 4: 40, 5: 50}

Example 2:

{1: 10, 2: 30, 3: 30, 5: 40, 6: 60} # k>>> d1={1:10,2:20,3:30} # key 2 value is 20
>>> d2={2:30,5:40,6:60} #key 2 value is 30
>>> d1.update(d2)
>>> print d1
# key 2 value is replaced with 30 in d1

Removing an item from dictionary

We can remove item from the existing dictionary by using del key word.

syntax:

del dicname[key]

Example:

>>> A={"mon":"monday","tue":"tuesday","wed":"wednesday","thu":"thursday"}
>>> del A["tue"]
>>> print A
{'thu': 'thursday', 'wed': 'wednesday', 'mon': 'monday'}

Dictionary functions and methods

cmp()

This is used to check whether the given dictionaries are same or not. If both are same, it will return zero, otherwise return 1 or -1. If the first dictionary having more number of items, then it will return 1, otherwise return -1.

Syntax:

cmp(d1,d2) # d1and d2 are dictionary.
returns 0 or 1 or -1

Example:

>>> D1={'sun':'Sunday','mon':'Monday','tue':'Tuesday','wed':'Wednesday','thu':'Thursday','fri':'Friday','sat':'Saturday'}
>>> D2={'sun':'Sunday','mon':'Monday','tue':'Tuesday','wed':'Wednesday','thu':'Thursday','fri':'Friday','sat':'Saturday'}
>>> D3={'mon':'Monday','tue':'Tuesday','wed':'Wednesday'}
>>> cmp(D1,D3) #both are not equal
1
>>> cmp(D1,D2) #both are equal
0
>>> cmp(D3,D1)
-1

len()

This method returns number of key-value pairs in the given dictionary.

Syntax:

len(d) # d dictionary

clear()

It removes all items from the particular dictionary.

Example:

>>> D={'mon':'Monday','tue':'Tuesday','wed':'Wednesday'}
>>> print D
{'wed': 'Wednesday', 'mon': 'Monday', 'tue': 'Tuesday'}
>>> D.clear()
>>> print D
{}

get(k, x)

There are two arguments (k, x) passed in get() method. The first argument is key value, while the second argument is corresponding value. If a dictionary has a given key (k), which is equal to given value (x), it returns the corresponding value (x) of given key (k). However, if the dictionary has no key-value pair for given key (k), this method returns the default values same as given value (x). The second argument is optional. If omitted and the dictionary has no key equal to the given key value, then it returns None.

syntax:

D.get (k, x) # D dictionary, k key and x value

Example:

>>> D={'sun':'Sunday','mon':'Monday','tue':'Tuesday','wed':'Wednesday','thu':'Thursday','fri':'Friday','sat':'Saturday'}
>>> D.get('wed',"wednesday") # corresponding value wed
'Wednesday'
>>> D.get("fri","monday") # default value of fri
'Friday'
>>> D.get("mon") # default value of mon
'Monday'
>>> D.get("ttu") # None
>>>

has_key()

This function returns True, if dictionary has a key, otherwise it returns False.

syntax:

D.has_key(k) #D dictionary and k key

items()

It returns the content of dictionary as a list of key and value. The key and value pair will be in the form of a tuple, which is not in any particular order.

syntax:

D.items() # D dictionary

Example:

>>> D={'sun':'Sunday','mon':'Monday','tue':'Tuesday','wed':'Wednesday','thu':'Thursday','fri':'Friday','sat':'Saturday'}
>>> D.items()
[('wed', 'Wednesday'), ('sun', 'Sunday'), ('thu', 'Thursday'), ('tue', 'Tuesday'), ('mon','Monday'), ('fri', 'Friday'), ('sat', 'Saturday')]

Note: items() is different from print command because, in print command dictionary values are written in {}

keys()

It returns a list of the key values in a dictionary, , which is not in any particular order.

Syntax:

D.keys( ) #D dictionary

Example:

>>> D={'sun':'Sunday','mon':'Monday','tue':'Tuesday','wed':'Wednesday','thu':'Thursday','fri':'Friday','sat':'Saturday'}
>>> D.keys()
['wed', 'sun', 'thu', 'tue', 'mon', 'fri', 'sat']
>>>

values()

It returns a list of values from key-value pairs in a dictionary, which is not in any particular order. However, if we call both the items() and values() method without changing the dictionary’s contents between these two (items() and values()), Python guarantees that the order of the two results will be the same.

syntax:

D.values() # D values

Example:

>>> D={'sun':'Sunday','mon':'Monday','tue':'Tuesday','wed':'Wednesday','thu':'Thursday','fri':'Friday','sat':'Saturday'}
>>> D.values()
['Wednesday', 'Sunday', 'Thursday', 'Tuesday', 'Monday', 'Friday', 'Saturday']
>>> D.items()
[('wed', 'Wednesday'), ('sun', 'Sunday'), ('thu', 'Thursday'), ('tue', 'Tuesday'), ('mon', 'Monday'), ('fri', 'Friday'), ('sat', 'Saturday')]

Get key by value in dictionary

Basically we need to separate the dictionary’s value in a list, find the position of the value you have and get the key at the position.

Example:

>>> myDict
{'age': 20, 'college': 'Army Institute of Technology', 'name': 'amit'}
>>> myDict.keys()[myDict.values().index('amit')]
'name'
>>> 

NOTE: From python3, we need to cast the dic.keys() and dic.values() in list() explicitly.

With the help of index() function we get the index of particular item passed as argument.

To find the value of a particular key, you can also iterate over keys (but that’s not a good idea).

Thank you 👏

Get familiar with lists

What is a list
Like a String, list also is sequence data type. It is an ordered set of values enclosed in square brackets []. Values in the list can be modified, i.e. it is mutable.

For accessing an element of the list, indexing is used.

Syntax:

listName[index] #(variable name is name of the list).

Index here, has to be an integer value- which can be positive or negative. Positive value of index means counting forward from beginning of the list and negative value means counting backward from end of the list. Remember the result of indexing a list is the value of type accessed from the list.

Let’s look at some example of simple list:

>>> L1 = [1, 2, 3, 4] # list of 4 integer elements.

>>> L2 = [Delhi, Chennai, Mumbai] #list of 3 string elements.

>>> L3 = [ ] # empty list i.e. list with no element

>>> L4 = [abc, 10, 20] # list with different types of elements

>>> L5 = [1, 2, [6, 7, 8], 3] # A list containing another list known as nested list

To change the value of element of list, we access the element & assign the new value.

Example:

>>> print L1 # let‟s get the values of list before change
>>> L1 [2] = 5
>>> print L1 # modified list
[1, 2, 5, 4]

NOTE: An Index Error appears, if you try and access element that does not exist in the list.

Creating a list

List can be created in many ways:

i) By enclosing elements in [ ], as we have done in above examples.

ii) Using other Lists

Example:

L5=L1 [:]

Here L5 is created as a copy of L1.

>>> print L5
L6 = L1 [0:2]
>>> print L6
# will create L6 having first two elements of L1.

iii) List comprehension:

Example:

>>> S= [x**2 for x in range (10)]
>>> print S
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

In mathematical terms, S can be defined as S = {x 2 for: x in (0.....9)}. So, we can say that list comprehension is short-hand for creating list.

iv) Using built-in object

L = list () will create an empty list.

or

L = list [(1, 2, 3, 4)]

A single new list is created every time, you execute [ ]. We have created many different lists each using [ ]. But if a list is assigned to another variable, a new list is not created.

Example:

A = []
B = A # Will also create one list mapped to both
C = []

You can try to check the address of A and B.

if id(A) == id(B):
  print 'yes'

# printing the address
print hex(id(A))
print hex(id(B))

Accessing an element of list

For accessing an element, we use index and we have already seen example doing so. To access an element of list containing another list, we use pair of index. Lets access elements of L5 list. Also a sub-list of list can be accessed using list slice.

List Slices

Slice operator works on list also. We know that a slice of a list is its sub-list. For creating a list slice, we use [n:m] operator.

>>> print L5 [0]
1
>>> print L5 [2]
[6, 7, 8]
>>> print L5 [2] [0]
6
>>> print L5 [2] [2]
8
>>> L1 [1:2]
[2]

list[n:m] will return the part of the list from n th element to m th element, including the first element but excluding the last element. So the resultant list will have m-n elements in it. Slices are treated as boundaries, and the result will contain all the elements between boundaries.

Its Syntax is:

seq = L [start: stop: step]

Where start, stop & step - all three are optional. If you omit first index, slice starts from 0 and omitting of stop will take it to end. Default value of step is 1.

Example

For list L2 containing [“Delhi”, “Chennai”, “Mumbai”]

>>> L2 [0:2]
[Delhi, Chennai]

>>> list = [10, 20, 30, 40, 50, 60]
>>> list [::2] # produce a list with every alternate element
[10, 30, 50]

>>> list [4:] # will produce a list containing all the elements from 5 th position till end
[50, 60]

>>> list [:3]
[10, 20, 30]
>>> list [:]
[10, 20, 30, 40, 50, 60]

>>> list [-1] # „-1‟ refers to last elements of list
60

Note: Since lists are mutable, it is often recommended to make a copy of it before performing operation that change a list.

Traversing a List

Let us visit each element (traverse the list) of the list to display them on screen. This can be done in many ways:

  • while loop
i = 0
while i < len [L1]:
    print L1 [i],
i + = 1

will produce following output

1 2 5 4
  • for loop
for i in L1:
    print i,

or

for i in range ( len (L1)):
    print L1 [i],

range() function is used to generate, indices from 0 to len -1; with each iteration i gets the index of next element and values of list are printed.

Note: for loop in empty list is never executed

Using enumerate

The enumerate() function adds a counter to an iterable. So for each element in cursor, a tuple is produced with (counter, element); the for loop binds that to row_number and row, respectively.

Example:

>>> elements = ('foo', 'bar', 'baz')
>>> for elem in elements:
...     print elem
... 
foo
bar
baz
>>> for count, elem in enumerate(elements):
...     print count, elem
... 
0 foo
1 bar
2 baz

By default, enumerate() starts counting at 0 but if you give it a second integer argument, it’ll start from that number instead:

Example:

>>> for count, elem in enumerate(elements, 42):
...     print count, elem
... 
42 foo
43 bar
44 baz

Refered from here

Appending in the list

Appending a list is adding more element(s) at the end of the list. To add new elements at the end of the list, Python provides a method append ( ).

Syntax is:

# List. append (item)

L1. append (70)

This will add 70 to the list at the end, so now 70 will be the 5 th element of the list, as it already have 4 elements.

Using append(), only one element at a time can be added. For adding more than one element, extend() method can be used, this can also be used to add elements of another list to the existing one.

Example:

>>> A = [100, 90, 80, 50]
>>> L1. extend (A)
>>> print L1
[1, 2, 5, 4, 70, 100, 90, 80, 50]

will add all the elements of list A at the end of the list L1.

>>>print A
[100, 90, 80, 50]

Remember: A remains unchanged.

Updating array elements

Updating an element of list is, accomplished by accessing the element & modifying its value in place. It is possible to modify a single element or a part of list. For first type, we use index to access single element and for second type, list slice is used. We have seen examples of updations of an element of list.

Lets update a slice.

Example1:

>>> L1 [1:2] = [10, 20]
>>> print L1
# will produce
[1, 10, 20, 4, 70, 100, 90, 80, 50]

Example2:

>>> A=[10, 20, 30, 40]
>>> A [1:4] = [100]
>>> print A
# will produce
[10, 100]

As lists are sequences, they support many operations of strings. For example, operator + & * results in concatenation & repetition of lists. Use of these operators generate a new list.

Example:

>>> a= L1+L2

# will produce a 3 rd list a containing elements from L1 & then L2. a will contain
[1, 10, 20, 4, 70, 100, 90, 80, 50, Delhi, Chennai, Mumbai]

>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]

>>> ['Hi!']* 3
['Hi!', 'Hi!', 'Hi!']

It is important to know that + operator in lists expects the same type of sequence on both the sides otherwise you get a type error.

If you want to concatenate a list and string, either you have to convert the list to string or string to list.

Example:

>>> str([11, 12]) + 34
'[11, 12] 34'
>>> [11,12] + 34
'[11, 12] 34'


>>> [11, 12] + list (34)
[11, 12, '3', '4']
>>> [11, 12] + [3, 4]

Deleting Elements

It is possible to delete/remove element(s) from the list. There are many ways of doing:

(i) If index is known, we can use pop() or del

(ii) If the element is known, not the index, remove () can be used.

(iii) To remove more than one element, del() with list slice can be used.

(iv) Using assignment operator.

Let us study all the above methods in details:

Pop()

It removes the element from the specified index, and also return the element which was removed.

Example:

>>> L1 = [1, 2, 5, 4, 70, 10, 90, 80, 50]
>>> a= L1.pop (1) # here the element deleted will be returned to ‘a’
>>> print L1
[1, 5, 4, 70, 10, 90, 80, 50]
>>> print a
2

# If no index value is provided in pop ( ), then last element is deleted.
>>>L1.pop ( )
50

del removes the specified element from the list, but does not return the deleted value.

>>> del L1 [4]
>>> print L1
[1, 5, 4, 70, 90, 80]

remove ()

In case, we know the element to be deleted not the index, of the element, then remove() can be used.

>>> L1. remove (90) # will remove the value 90 from the list

>>> print L1
[1, 5, 4, 70, 80]

del () with slicing

Example:

>>> del L1 [2:4]
>>>print L1
[1, 5, 80]

will remove 2 nd and 3 rd element from the list. As we know that slice selects all the elements up to 2nd index but not the 2nd index element. So 4th element will remain in the list.

>>> L5 [1:2] = []

# Will delete the slice
>>>print L5
[1, [6, 7, 8], 3]

NOTE:

All the methods, modify the list, after deletions.

If an out of range index is provided with del () and pop (), the code will result in to run-time error.

del can be used with negative index value also.

Other functions & methods

insert ()

This method allows us to insert an element, at the given position specified by its index, and the remaining elements are shifted to accommodate the new element.

insert() requires two arguments- index value and item value.

syntax is:

list. insert (index, item)

Index specifies the position (starting from 0) where the element is to be inserted. Item is the element to be inserted in the list. Length of list changes after insert operation.

Example

>>> L1.insert (3,100)
>>>print L1
# will produce
[1, 5, 80, 100]

Note: If the index specified is greater then len (list) the object is inserted in the last and if index is less than zero, the object is inserted at the beginning.

>>> print len(L1)
4
>>> L1.insert (6, 29)
>>> L1.insert (-2, 46)
>>>print L1
# will produce
[46, 1, 5, 80, 100, 29]

reverse ()

This method can be used to reverse the elements of the list in place

syntax is:

list.reverse()

Method does not return anything as the reversed list is stored in the same variable.

Example

>>> L1.reverse()
>>> print L1
# will produce
[29, 100, 80, 5, 1, 46]

Following will also result into reversed list.

>>>L1 [: : -1]

As this slices the whole sequence with the step of -1 i.e. in reverse order.

sort()

For arranging elements in an order Python provides a method sort () and a function sorted (). sort () modifies the list in place and sorted () returns a new sorted list.

Syntax are:

sort ([cmp [, key [, reverse]]])

and

sorted (list [, cmp [, key [, reverse]]])

Parameters mentioned in [] are optional in both the cases. These parameters allow us to customize the function/method.

cmp, argument allow us to override the default way of comparing elements of list. By default, sort determines the order of elements by comparing the elements in the list against each other. To overside this, we can use a user defined function which should take two values and return -1 for less than, 0 for equal to and 1 for greater than.

Key argument is preferred over cmp as it produces list faster.

Example 1:

The parameter key is for specifying a function that transforms each element of list before comparison. We can use predefined functions or a user defined function here. If its user defined then, the function should take a single argument and return a key which can be used for sorting purpose.

Reverse parameter can have a boolean value which is used to specify the order of arranging the elements of list. Value True for reverse will arrange the elements of list in descending order and value False for reverse will arrange the elements in ascending order. Default value of this parameter is False.

sorted () function also behaves in similar manner except for it produce a new sorted list, so original is not changed. This function can also be used to sort any iterable collection. As sort() method does not create a new list so it can be little faster.

>>> L1.sort()
>>> print L1
# will produce
[1, 5, 29, 46, 80, 100]
>>> L2.sort ( )
>>> print L2
# will produce
['Chennai', 'Delhi', 'Mumbai']
>>> L2.sort (key=len)
# will produce
['Delhi', 'Mumbai', 'Chennai']

Here we have specified len() built in function, as key for sorting. So the list will get sorted by the length of the strings, i.e., from shorted to longest. sort will call len() function for each element of list and then these lengths will be used for arranging elements.

Example 2:

>>> L4.sort()
>>> print L4
# will produce
[10, 20, 30, 'abc']
>>>L4.sort (reverse = True)
['abc', 30, 20, 10]
>>> def compare (str):
	return len (str)
>>> L2.sort (key=compare)
>>> L2
['Delhi', 'Mumbai', 'Chennai]

Passing list to a function (List as arguments)

Arguments are passed by assignment. The rationale behind this is two fold:

  1. The parameter passed in is actually a reference to an object (but the reference is passed by value).
  2. Some data types are mutable, but others aren’t.

When a list is passed to the function, the function gets a reference to the list. So if the function makes any changes in the list, they will be reflected back in the list.

In a more generalized form,

  • If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart’s delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you’re done, the outer reference will still point at the original object.

  • If you pass an immutable object to a method, you still can’t rebind the outer reference, and you can’t even mutate the object.

Example:

def try_to_change_list_contents(the_list):
    print('got', the_list)
    the_list.append('four')
    print('changed to', the_list)

outer_list = ['one', 'two', 'three']

print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)

Here parameter outer_list and argument the_list are alias for same object. So any changes made in outer_list will be reflected to the_list as lists as mutable.

Output:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

Note: Here, it becomes important to distinguish between the operations which modifies a list and operation which creates a new list. Operations which create a new list will not affect the original (argument) list.

Let’s look at some examples to see when we have different lists and when an alias is created.

>>> a = [2, 4, 6]
>>> b = a

will map b to a. To check whether two variables refer to same object (i.e. having same value), we can use is operator. So in our example:

>>> a is b
# will return "True"
>>> a = [2, 4, 6]
>>> b = [2, 4, 6]
>>> a is b
False

In first example, Python created one list, reference by a & b. So there are two references to the same object b. We can say that object [2, 4, 6] is aliased as it has more than one name, and since lists are mutable. So changes made using a will affect b.

>>> a [1] = 10
>>> print b
# will print
[2, 10, 6]

Thank you 👏

Get familiar with strings

In python, consecutive sequence of characters is known as a string. An individual character in a string is accessed using a subscript (index). The subscript should always be an integer (positive or negative). A subscript starts from 0.

# Declaring a string in python
>>>myfirst=“Save Earth”
>>>print myfirst

To access the last character of the string

>>>print myfirst[-1]
h

To access the third last character of the string

>>>print myfirst[-3]
r

Important points about accessing elements in the strings using subscripts

  • Positive subscript helps in accessing the string from the beginning.
  • Negative subscript helps in accessing the string from the end.
  • Subscript 0 or –ve n(where n is length of the string) displays the first element.
  • Subscript 1 or –ve (n-1) displays the second element.

Note: Python does not support character data type. A string of size 1 can be treated as characters.

Creating and initializing strings

A literal/constant value to a string can be assigned using:

  • single quotes
  • double quotes
  • triple quotes.
  • By invoking raw_input() method

Example:

>>>raw_input()
Right to education
'Right to education'

As soon as the interpreter encounters raw_input method, it waits for the user to key in the input from a standard input device (keyboard) and press Enter key. The input is converted to a string and displayed on the screen.

  • By invoking input() method.

Example:

>>>str=input("Enter the string")
Enter the string hello
NameError: name 'hello' is not defined

Python interpreter was not able associate appropriate data type with the entered data. So a NameError is shown. The error can be rectified by enclosing the given input i.e. hello in quotes as shown below.

>>>str=input("Enter the String")
Enter the String "Hello"
>>> print str
Hello

Strings are immutable

Strings are immutable means that the contents of the string cannot be changed after it is created.

Let us understand the concept of immutability with help of an example.

>>>str='honesty'
>>>str[2]='p'
# TypeError: 'str' object does not support item assignment

Python does not allow the programmer to change a character in a string. As shown in the above example, str has the value honesty. An attempt to replace n in the string by p displays a TypeError.

Traversing a string

Traversing a string means accessing all the elements of the string one after the other by using the subscript. A string can be traversed using: for loop or while loop.

String traversal using for loop

A=‟Welcome‟
>>>for i in A:
	print i

String traversal using while loop

A=‟Welcome‟
>>>i=0
>>>while i<len(A)
	print A[i]

Strings Operations

  • + (Concatenation)
  • * (Repetition ) : The * operator repeats the string on the left hand side times the value on right hand side.
  • in (Membership)
  • not in
  • range (start, stop[,step]): This function is already discussed in previous chapter.
  • Slice[n:m]: The Slice[n : m] operator extracts sub parts from the strings.

More on string Slicing

Consider the given string

A = 'Save Earth'

Let’s understand Slicing in strings with the help of few examples.

>>>A=‟Save Earth‟
>>> print A[1:3]
av

The print statement prints the substring starting from subscript 1 and ending at subscript 3 .

>>>print A[3:]
'e Earth'

Omitting the second index, directs the python interpreter to extract the substring till the end of the string.

>>>print A[:3]
Sav

Omitting the first index, directs the python interpreter to extract the substring before the second index starting from the beginning.

>>>print A[:]
'Save Earth'

Omitting both the indices, directs the python interpreter to extract the entire string starting from 0 till the last index

>>>print A[-2:]
'th'

For negative indices the python interpreter counts from the right side (also shown above). So the last two letters are printed.

>>>Print A[:-2]
'Save Ear'

Omitting the first index, directs the python interpreter to start extracting the substring form the beginning. Since the negative index indicates slicing from the end of the string. So the entire string except the last two letters is printed.

String methods & built in functions

  • len()
  • capitalize()
  • find(sub[,start[, end]])
  • isalnum()
  • isalpha()
  • isdigit()
  • lower()
  • islower()
  • upper()
  • isupper()
  • lstrip()
  • rstrip()
  • isspace()
  • istitle()
  • replace(old, new)
  • join ()
  • swapcase()
  • partition(sep)
  • split([sep[,maxsplit]])

Note: In the table given above, len( ) is a built in function and so we don‟t need import the string module. For all other functions import string statement is required for their successful execution.

Lets discuss some interesting strings constants defined in string module:

string.ascii_uppercase:

The command displays a string containing uppercase characters .

string.ascii_lowercase:

The command displays a string containing all lowercase characters .

string.ascii_letters:

The command displays a string containing both uppercase and lowercase characters.

string.digits:

The command displays a string containing digits.

string.hexdigits:

The command displays a string containing hexadecimal characters.

string.octdigits:

The command displays a string containing octal characters.

string.punctuations:

The command displays a string containing all the punctuation characters.

string.whitespace:

The command displays a string containing all ASCII characters that are considered whitespace. This includes the characters space, tab, linefeed, return, formfeed, and vertical tab.

string.printable:

The command displays a string containing all characters which are considered printable like letters, digits, punctuations and whitespaces.

Note: Import string module to get the desired results with the commands mentioned above.

Thank you 🎂 👏

Python functions

A function is a named sequence of statement(s) that performs a computation. Function can be categorized as belongings to:

  1. Modules function
  2. Built in
  3. User defined

Function in modules

  • A module is a file containing Python definitions (i.e. functions) and statements.
  • Definitions from the module can be used within the code of a program.
  • To use these modules in the program, a programmer needs to import the module. Once you import a module, you can reference (use), any of its functions or variables in your code.

Ways to import modules in program:

  1. import
  2. from

import

It is simplest and most common way to use modules in our code.

Its syntax is:

import modulename1 [,modulename2, ---------]

Example:

>>> import math

On execution of this statement, Python will:

  1. search for the file „math.py‟.
  2. Create space where modules definition & variable will be created,
  3. then execute the statements in the module.

Now the definitions of the module will become part of the code in which the module was imported.

Thank you 🎂 👏

Scopes and namespaces in python

Namespaces

The variables refer to an object and they are created when they are first assigned a value. In fact the variables are bound to their values using the assignment operator(=). So a namespace is a place where a variable’s name is stored and the value of the variable is bound to this namespace.

A namespace is a mapping from names to objects. It is a thing which associates the names with its values. In simple terms, it is a place where name lives. They are created at different moments and have different lifetimes. The examples of namespaces are:

  • Built-in names: These consist of functions such as max() , min() and built-in exception names. This namespace is created when the Python interpreter starts up, and is never deleted. The built-in names actually also live in a module called __ builtin__.

  • Global names in a module: The global namespace for a module is created when the module definition is read in and normally lasts until the interpreter quits. The statements executed by the top-level invocation of the interpreter, either read from a script file or interactively, are considered to be part of a module called __main__ and they have their own global namespace.

  • Local names in a function invocation: The local namespace for a function is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function. Even each recursive invocation has its own local namespace.

If we talk about classes and objects, the set of attributes of an object also form a namespace. It must be noted that there is absolutely no relation between names in different namespaces. Two different modules may both define same function without any confusion because the functions are prefixed with the module name. That means module1.cmp() has no relation with module2.cmp().

Scope Rules

A scope is a region of a Python program where a namespace is directly accessible. The location where the names are assigned in the code determines the scope of visibility of the name in that code. Although scopes are determined statically i.e. during creation of the program, yet they are used dynamically i.e. during execution of the program. At any time during execution, there are at least four main things to remember in the context of scope rules:

  1. In Python, names of all types of variables are treated in same manner. That means numbers, strings, functions, types, modules, classes - all are treated in the same way. Also a name can refer to only one thing at a time. For example, consider the following program:
var = 10 + 5
print var
def var(y):
	return y*10
	print var
var = "Hello"
print var

In the code given above, the variable var is bound to 15(10 + 5). Then def var(y) binds var to a function. The previous binding of var to 15 is lost and is replaced by the function. Thereafter var is bound to a string, so its binding with the function is no longer existing.

  1. The scope of a variable is its enclosing function or class or file(module). As discussed before, each name belongs to a namespace. For example, if a variable is created in a particular function, then its scope is that function only, since that function creates its own namespace where it resides. So any variable inside the function will be local to that namespace. In the following example, the scope of the variable x is the test function.
def test():
	x = 5
	print x

Now let us modify the program -

x = 10
def exam():
	print x

def test():
	x = 5
	print x

def marks(x):
	print x

print x
exam()
test()
marks(20)

On executing the above code, the output will be

10
10
5
20

The first line creates a variable x that belongs to the namespace of the file, so its scope is the entire file. Hence 10 is displayed. The exam function creates its namespace, but that namespace doesn’t have an x in it. As Python doesn’t find x there, it checks the next larger enclosing namespace and finds x. So exam uses the variable x defined at the top and displays 10.

However, the test function defines its own variable named x with value 5, which has higher priority over the first definition of x. So any mention of x within the test function will refer to that x, hence displaying 5. The marks function also has an x in its own namespace, just like test function has. So x gets bound to whatever value is passed as an argument to marks function (20 in the given example). Hence the outer x is shadowed again in this function displaying the output as 20.

  1. The names always belong to the namespace where they are bound, irrespective of whether they are bound before or after they are referred. This is the reason which makes Python a lexically scoped language. The variable scopes are determined entirely by the locations of the variables in the source code of your program files, not by function calls. If a binding for a variable appears anywhere inside a function, the variable name is local to that function. Let us understand this with the help of an example:
x = 10
def func1():
	x=50
	print x


def func2():
	print x
	x=25

	
def func3(p):
	if p<10:
		x=2
	print x


func1()
func2()
func3(20)
func3(5)

In the above example, the func1 function creates a local variable x in its own namespace, shadowing the outer variable x. So the line print x prints 50. The func2 function also has a local variable x in its namespace but the assignment to x is after the print statement. The local variable x shadows the outer x, even though the local x is initially not bound to anything. The line print x looks for x in the local namespace, finds that it is not bound to anything, and so the reference to x leads to an error (an Unbound Local Error occurs). Similarly, in func3(), the variable x is local.

When we call func3(20), the line x = 2 is not executed, so print x causes an error. But when we call func3(5), the line x = 2 is executed , so print x prints 2.

  1. Names declared with global keyword have to be referred at the file level. This is because the global statement indicates that the particular variable lives in the global scope. If no global statement is being used, the assignment to the name is always in the innermost local scope. Consider the following example:
x=5
def func1():
	x=2
	x=x+1

def func2():
	global x
	x=x+1

print x
func1()
print x
func2()
print x

The above example prints 5; then calling func1() it prints 3. This is because func1 only increments a local x. Then func2()increments the global x and prints 6.

LEGB Rule

From the examples discussed above, we come up to the LEGB rule. According to this rule, when a name is encountered during the execution of the program, it searches for that name in the following order:

  • L. Local - It first makes a local search i.e. in current def statement. The import statements and function definitions bind the module or function name in the local scope. In fact, all operations that introduce new names use the local scope.

  • E. Enclosing functions - It searches in all enclosing functions, form inner to outer.

  • G. Global (module) - It searches for global modules or for names declared global in a def within the file.

  • B. Built-in (Python) - Finally it checks for any built in functions in Python.

The examples given above give the output according to the LEGB rule only.

Thank you 🎂 👏