Sie sind auf Seite 1von 80

6/17/2019 Main

Overview
In [2]:

isinstance(2.5, float)

Out[2]:

True

In [2]:

2 + 3

Out[2]:

_ is a special variable in the python shell which holds the result of the last operation

In [5]:

Out[5]:

In [11]:

import keyword
keyword.iskeyword("elif")

Out[11]:

True

file:///Users/adityasingh/Downloads/Main.html 1/39
6/17/2019 Main

Keywords

False
True
None
class
finally
is
return
continue
for
lambda
try
def
from
nonlocal
while
and
del
global
not
with
as
elif
if
or
yield
assert
else
import
pass
break
except
in
raise

Printing without newline

file:///Users/adityasingh/Downloads/Main.html 2/39
6/17/2019 Main

In [12]:

# Python 3 code for printing on the same line printing

print("aditya", end =" ")


print("aditya")

# array
a = [1, 2, 3, 4]

# printing a element in same


# line
for i in range(4):
print(a[i], end =" ")

aditya aditya
1 2 3 4

Dynamic Typing : Python is a dynamically typed language where variable names are bound to different
values, possibly of varying types, during program execution.The assignment operator simply creates an
association between a name and a value. Although each value has an associated type such as an integer or
string, variable names are untyped and can be made to refer to any type of data during execution.This is
different from C, for example, in which a name represents a fixed type, size, and location in memory into
which a value is stored.

Every piece of data stored in a program is an object. Each object has an identity, a type (which is also known
as its class), and a value. For example, when you write a = 42, an integer object is created with the value of
42. You can view the identity of an object as a pointer to its location in memory. a is a name that refers to
this specific location. The type of an object, also known as the object’s class, describes the internal
representation of the object as well as the methods and operations that it supports. When an object of a
particular type is created, that object is sometimes called an instance of that type. After an instance is
created, its identity and type cannot be changed. If an object’s value can be modified, the object is said to
be mutable. If the value cannot be modified, the object is said to be immutable. An object that contains
references to other objects is said to be a container or collection. Most objects are characterized by a
number of data attributes and methods. An attribute is a value associated with an object. A method is a
function that performs some sort of operation on an object when the method is invoked as a function.

Built-In Types
There are approximately a dozen built-in data types that are used to represent most of the data used in
programs. These are grouped into a few major categories as shown below. (NoneType, Numeric Types,
Strings and Sequence Types)

None Type
The None type denotes a null object (an object with no value). Python provides exactly one null object,
which is written as None in a program. This object is returned by functions that don’t explicitly return a value.
None is frequently used as the default value of optional arguments, so that the function can detect whether
the caller has actually passed a value for that argument. None has no attributes and evaluates to False in
Boolean expressions.

file:///Users/adityasingh/Downloads/Main.html 3/39
6/17/2019 Main

In [63]:

print(type(4))
print(type(3.2))
print(type(3+2j))
print(type(True))
print(type("hello world"))
print(type((3,4)))
print(type([3,4]))
print(type(set([3,4])))
print(type(frozenset([3,4,5,6])))
print(type(None))

<class 'int'>
<class 'float'>
<class 'complex'>
<class 'bool'>
<class 'str'>
<class 'tuple'>
<class 'list'>
<class 'set'>
<class 'frozenset'>
<class 'NoneType'>

Mutable objects:
list
dict
set
byte array

Immutable objects:
int
float
complex
string
tuple
frozen set
bytes
range
bool

Custom classes are generally mutable. To simulate immutability in a class, one should override attribute
setting and deletion to raise exceptions.

In [8]:

a = "hello"
print(id(a))

a = "world"
print(id(a))

4546224000
4546223664

file:///Users/adityasingh/Downloads/Main.html 4/39
6/17/2019 Main

In [9]:

a = [2,3,4]
print(id(a))

a.append(7)
print(id(a))

4546257480
4546257480

file:///Users/adityasingh/Downloads/Main.html 5/39
6/17/2019 Main

Numeric Types
The identifiers True and False are interpreted as Boolean values with the integer values of 1 and 0,
respectively. A number such as 1234 is interpreted as a decimal integer. To specify an integer using octal,
hexadecimal, or binary notation, precede the value with 0, 0x, or 0b, respectively (for example, 0644,
0x100fea8, or 0b11101010). Integers in Python can have an arbitrary number of digits, so if you want to
specify a really large integer, just write out all of the digits, as in 12345678901234567890. However, you
might see large numbers written with a trailing l (lowercase L) or L character, as in 12345678901234567890L.
This trailing L is related to the fact that Python internally represents integers as either a fixed-precision
machine integer or an arbitrary precision long integer type depending on the magnitude of the value.
Numbers such as 123.34 and 1.2334e+02 are interpreted as floating-point numbers. An integer or floating-
point number with a trailing j or J, such as 12.34J, is an imaginary number. You can create complex numbers
with real and imaginary parts by adding a real number and an imaginary number, as in 1.2 + 12.34J.

Python uses five numeric types: Booleans, integers, long integers, floating-point numbers, and complex
numbers. Except for Booleans, all numeric objects are signed. All numeric types are immutable. Booleans
are represented by two values: True and False. The names True and False are respectively mapped to the
numerical values of 1 and 0. Integers represent whole numbers in the range of –2147483648 to 2147483647
(the range may be larger on some machines). Long integers represent whole numbers of unlimited range
(limited only by available memory). Although there are two integer types, Python tries to make the distinction
seamless (in fact, in Python 3, the two types have been unified into a single integer type).

Sequence Types
Sequences represent ordered sets of objects indexed by non-negative integers and include strings, lists,
and tuples. Strings are sequences of characters, and lists and tuples are sequences of arbitrary Python
objects. Strings and tuples are immutable; lists allow insertion, deletion, and substitution of elements. All
sequences support iteration.

Operators and methods that you can apply to all sequence types. Element i of sequence s is selected using
the indexing operator s[i], and subsequences are selected using the slicing operator s[i:j] or extended slicing
operator s[i:j:stride] The length of any sequence is returned using the built-in len(s) function.You can find the
minimum and maximum values of a sequence by using the built-in min(s) and max(s) functions. However,
these functions only work for sequences in which the elements can be ordered (typically numbers and
strings). sum(s) sums items in s but only works for numeric data.

Operators applicable to Mutable sequences

file:///Users/adityasingh/Downloads/Main.html 6/39
6/17/2019 Main

Mapping Types
A mapping object represents an arbitrary collection of objects that are indexed by another collection of
nearly arbitrary key values. Unlike a sequence, a mapping object is unordered and can be indexed by
numbers, strings, and other objects. Mappings are mutable. Dictionaries are the only built-in mapping type
and are Python’s version of a hash table or associative array. You can use any immutable object as a
dictionary key value (strings, numbers, tuples, and so on). Lists, dictionaries, and tuples containing mutable
objects cannot be used as keys (the dictionary type requires key values to remain con- stant). To select an
item in a mapping object, use the key index operator m[k], where k is a key value. If the key is not found, a
KeyError exception is raised. The len(m) function returns the number of items contained in a mapping object.

(more on dictionaries later ....)

If the first statement of a module, class, or function definition is a string, that string becomes a
documentation string for the associated object, as in the following example:

In [60]:

def fact(n):
"This function computes a factorial"
if (n <= 1):
return 1
else:
return n * fact(n - 1)

In [61]:

print(fact.__doc__)

This function computes a factorial

In [6]:

year = 1
principal = 1000
print("%3d %0.2f" % (year, principal)) #Python 3

1 1000.00

file:///Users/adityasingh/Downloads/Main.html 7/39
6/17/2019 Main

A newline terminates each statement. However, you can use a semicolon to separate statements on the
same line

print(format(year,"3d"),format(principal,"0.2f"))

In [11]:

a = 4
b = 5
if a < b:
print("Computer says Yes")
else:
print("Computer says No")

#To create an empty clause, use the pass statement

Computer says Yes

Python does not have a special switch or case statement for testing values. To handle multiple-test cases,
use the elif statement, like this:

In [15]:

suffix = ".htm"
if suffix == ".htm":
content = "text/html"
elif suffix == ".jpg":
content = "image/jpeg"
elif suffix == ".png":
content = "image/png"
else:
raise RuntimeError("Unknown content type")

To denote truth values, use the Boolean values True and False. All relational operators such as < and >
return True or False as results.

In [18]:

s = ['spam', 'hey']
if 'spam' in s:
has_spam = True
else:
has_spam = False

The in operator used in this example is commonly used to check whether a value is contained inside of
another object such as a string, list, or dictionary. It also returns True or False, so the preceding example
could be shortened to this:

In [20]:

has_spam = 'spam' in s

file:///Users/adityasingh/Downloads/Main.html 8/39
6/17/2019 Main

The following program opens a file and reads its contents line by line. The open() function returns a new file
object. By invoking methods on this object, you can perform various file operations.The readline() method
reads a single line of input, including the terminating newline. The empty string is returned at the end of the
file.

In [ ]:

f = open("foo.txt")
line = f.readline()
while line:
print(line)
line = f.readline()
f.close()
#lines = f.readlines() # Read all lines into a list

The program is simply looping over all the lines in the file foo.txt. Whenever a program loops over a
collection of data like this (for instance input lines, numbers, strings, etc.), it is commonly known as iteration.
Because iteration is such a common operation, Python provides a dedicated statement, for, that is used to
iterate over items. For instance, the same program can be written much more succinctly as follows:

In [ ]:

for line in open("foo.txt"):


print(line)

To make the output of a program go to a file

In [ ]:

f = open("out","w")
print("%3d %0.2f" % (year,principal),file=f)
#OR
f.write("%3d %0.2f\n" % (year,principal))

Although these examples have worked with files, the same techniques apply to the standard output and
input streams of the interpreter. For example, if you wanted to read user input interactively, you can read
from the file sys.stdin. If you want to write data to the screen, you can write to sys.stdout, which is the same
file used to output data produced by the print statement.

In [29]:

import sys
sys.stdout.write("Enter your name :")
name = sys.stdin.readline()

Enter your name :

In Python 3, the raw_input() function is called input(), but it works in exactly the same manner. It returns a
string. If you want to read integer, convert the input value using int(). int() will throw a ValueError if a non-
number input is given.

file:///Users/adityasingh/Downloads/Main.html 9/39
6/17/2019 Main

In [31]:

name = input("Enter your name :")

Enter your name :aditya

In [10]:

x = int(input())

hola

--------------------------------------------------------------------
-------
ValueError Traceback (most recent cal
l last)
<ipython-input-10-b18148c418c0> in <module>
----> 1 x = int(input())

ValueError: invalid literal for int() with base 10: 'hola'

Identifiers starting or ending with underscores often have special meanings. For example, identifiers starting
with a single underscore such as _foo are not imported by the from module import * statement. Identifiers
with leading and trailing double underscores such as init are reserved for special methods, and identifiers
with leading double underscores such as __bar are used to implement private class members.

Type conversions

int(a,base) : This function converts any data type to integer. ‘Base’ specifies the base in which string is if
data type is string
float() : This function is used to convert any data type to a floating point number
ord() : This function is used to convert a character to integer
hex() : This function is to convert integer to hexadecimal string
oct() : This function is to convert integer to octal string
tuple() : This function is used to convert to a tuple
set() : This function returns the type after converting to set
list() : This function is used to convert any data type to a list type
dict() : This function is used to convert a tuple of order (key,value) into a dictionary
str() : Used to convert integer into a string
complex(real,imag) : This function converts real numbers to complex(real,imag) number

Python Lists

file:///Users/adityasingh/Downloads/Main.html 10/39
6/17/2019 Main

Lists are sequences of arbitrary objects.You create a list by enclosing values in square brackets, as follows.
Lists can contain any kind of Python object, including other lists. The built-in function list(s) converts any
iterable type to a list. If s is already a list, this function constructs a new list that’s a shallow copy of s. The
s.append(x) method appends a new element, x, to the end of the list.The s.index(x) method searches the list
for the first occurrence of x. If no such element is found, a ValueError exception is raised. Similarly, the
s.remove(x) method removes the first occurrence of x from the list or raises ValueError if no such item exists.
The s.extend(t) method extends the list s by appending the elements in sequence t.

Lists supports many methods like append, extend, count, index, insert, pop, remove, reverse, sort. The built-
in function list(s) converts any iterable type to a list. If s is already a list, this function constructs a new list
that’s a shallow copy of s. The s.append(x) method appends a new element, x, to the end of the list.The
s.index(x) method searches the list for the first occurrence of x. If no such element is found, a ValueError
exception is raised. Similarly, the s.remove(x) method removes the first occurrence of x from the list or raises
ValueError if no such item exists. The s.extend(t) method extends the list s by appending the elements in
sequence t.

In [39]:

mylist = [ "Dave", "Mark", "Ann", "Phil" ]

In [40]:

mylist = [2,3,5,7,11,13]
mylist.append(17)
print(mylist)

#List assignment index out of range exception


#mylist[7]=10

[2, 3, 5, 7, 11, 13, 17]

file:///Users/adityasingh/Downloads/Main.html 11/39
6/17/2019 Main

Lists have a 0 based index. But when you go below 0, python again goes to the end of the list. But you
can wrap around the list only once.

In [3]:

mylist[-2]

Out[3]:

13

In [4]:

print(mylist[2:5])
print(mylist[:5]) #Slice index 0 to 5
print(mylist[4:]) #Slice from 4(inclusive) to the end of the list

test_list = mylist[:] #Copy the list and return a new one

[5, 7, 11]
[2, 3, 5, 7, 11]
[11, 13, 17]

You can also replace a range within a list

In [5]:

#Slice assignment. Replace a part of the list with a new list


mylist[2:4] = ["python", "java","c++"]
print(mylist)

#Deleting item at a particular location


del mylist[2]
print(mylist)

[2, 3, 'python', 'java', 'c++', 11, 13, 17]


[2, 3, 'java', 'c++', 11, 13, 17]

You can slice a list by using [x:y]. It will return a new list starting from element with index x upto
element with index y-1

In [6]:

#Concatenation
[1,2,3] + ['a','b','c']

Out[6]:

[1, 2, 3, 'a', 'b', 'c']

In [7]:

#Repetition
print([2]*4)
print(["a","b"]*3)

[2, 2, 2, 2]
['a', 'b', 'a', 'b', 'a', 'b']

file:///Users/adityasingh/Downloads/Main.html 12/39
6/17/2019 Main

In [8]:

#Membership
"aditya" in ["hello","aditya",2.4,"world"]

Out[8]:

True

Builtin List Functions


In [9]:

print(len([2,3,4]))
print(max([1,2,3,-4,-5]))
print(max(["aditya","singh","c"]))
# max/min should all be strings or numbers, otherwise it will throw an error

3
3
singh

In [10]:

k = [6,8,2,5,3,8,3,5,0]
#Returns a new list with sorted items. Unlike the sort() list method which sorts
the list in-place
print(sorted(k))
print(k)
print(sorted(k, reverse=True))

[0, 2, 3, 3, 5, 5, 6, 8, 8]
[6, 8, 2, 5, 3, 8, 3, 5, 0]
[8, 8, 6, 5, 5, 3, 3, 2, 0]

file:///Users/adityasingh/Downloads/Main.html 13/39
6/17/2019 Main

In [15]:

# python code to demonstrate working of sorted()

# initializing list
lis = [ 1 , 3, 5, 6, 2, 1, 3 ]

# using sorted() to print the list in sorted order


print ("The list in sorted order is : ")
for i in sorted(lis) :
print (i,end=" ")

print ("\r")

# using sorted() and set() to print the list in sorted order


# use of set() removes duplicates.
print ("The list in sorted order (without duplicates) is : ")
for i in sorted(set(lis)) :
print (i,end=" ")

The list in sorted order is :


1 1 2 3 3 5 6
The list in sorted order (without duplicates) is :
1 2 3 5 6

Using reversed(): reversed() is used to print the values of container in the descending order as declared.

In [16]:

# python code to demonstrate working of reversed()

# initializing list
lis = [ 1 , 3, 5, 6, 2, 1, 3 ]

# using revered() to print the list in reversed order


print ("The list in reversed order is : ")
for i in reversed(lis) :
print (i,end=" ")

The list in reversed order is :


3 1 2 6 5 3 1

For more complex custom sorting, sorted() takes an optional "key=" specifying a "key" function that
transforms each element before comparison. The key function takes in 1 value and returns 1 value, and the
returned "proxy" value is used for the comparisons within the sort. For example with a list of strings,
specifying key=len (the built in len() function) sorts the strings by length, from shortest to longest. The sort
calls len() for each string to get the list of proxy length values, and then sorts with those proxy values.

In [11]:

strs = ['ccc', 'aaaa', 'd', 'bb']


print(sorted(strs, key=len))

['d', 'bb', 'ccc', 'aaaa']

file:///Users/adityasingh/Downloads/Main.html 14/39
6/17/2019 Main

In [12]:

#Max and min method similar to sort - list must have objects of same type

print(min([4,5,6,7]))

#Will throw exception


#print(max([4,8,"two"]))

In [4]:

#Reverse the list in-place


testlist = [1,2,3,4,5,6,7]
testlist.reverse()
print(testlist)

[7, 6, 5, 4, 3, 2, 1]

List Methods

file:///Users/adityasingh/Downloads/Main.html 15/39
6/17/2019 Main

In [13]:

#append() vs extend()
lista = [2,3,4]
lista.append([4,5])
print(lista)

lista = [2,3,4]
lista.extend([4,5])
print(lista)

[2, 3, 4, [4, 5]]


[2, 3, 4, 4, 5]

In [14]:

print(mylist)
#new_element is becomes element at index 4, all elements are pushed to the righ
t. Insert can handle negative indices
mylist.insert(4,"new_element")
print(mylist)

#extend is concatenation function similar to + operator


mylist.extend([6,7])
print(mylist)

[2, 3, 'java', 'c++', 11, 13, 17]


[2, 3, 'java', 'c++', 'new_element', 11, 13, 17]
[2, 3, 'java', 'c++', 'new_element', 11, 13, 17, 6, 7]

In [15]:

#Returns index of the item if it exists, otherwise throws ValueError.


#If multiple elements exist, it returns the index first occurrance
lista = ["java","c++","python","perl","golang","javascript","c++"]
print(lista.index("c++"))

#Removes the first instance of the element if found, else throws ValueError
mylist.remove("java")
print(mylist)

1
[2, 3, 'c++', 'new_element', 11, 13, 17, 6, 7]

The s.sort() method sorts the elements of a list and optionally accepts a key function and reverse flag, both
of which must be specified as keyword arguments.The key function is a function that is applied to each
element prior to comparison during sorting. If given, this function should take a single item as input and
return the value that will be used to perform the comparison while sorting. Specifying a key function is useful
if you want to perform special kinds of sorting operations such as sorting a list of strings, but with case
insensitivity.The s.reverse() method reverses the order of the items in the list. Both the sort() and reverse()
methods operate on the list elements in place and return None.

file:///Users/adityasingh/Downloads/Main.html 16/39
6/17/2019 Main

In [16]:

#Sorts the list in place (does not return it)


newlist = [4,7,0,2,5,8,3,5,7]
#The sort() method returns None. So don't try to use it directly
print(newlist.sort())
print(newlist)

#Reverses the list in place (does not return it)


newlist.reverse()
print(newlist)

None
[0, 2, 3, 4, 5, 5, 7, 7, 8]
[8, 7, 7, 5, 5, 4, 3, 2, 0]

The default key method used by sort requires that all items in the list be of comparable types. That means
that using the sort method on a list containing both numbers and strings will raise an exception

In [17]:

#Pops the element at the index and returns it.


print(newlist.pop(3))
print(newlist)

print(newlist.pop())
print(newlist)

#Count returns the number of times a specific element occurs in a list


print(newlist.count(7))

5
[8, 7, 7, 5, 4, 3, 2, 0]
0
[8, 7, 7, 5, 4, 3, 2]
2

In [18]:

#Create a copy of the list and return the new list


copiedlist = newlist.copy()
print(copiedlist)

#Number of times a given element appears in a list


print(copiedlist.count(7))

[8, 7, 7, 5, 4, 3, 2]
2

In [19]:

#Check membership

print(3 in [4,5,3])
print(3 in ["one", "two", "three"])

True
False

file:///Users/adityasingh/Downloads/Main.html 17/39
6/17/2019 Main

Strings
Strings are also immutable. The operators and functions that work with them return new strings derived
from the original. The operators (in, +, and * ) and built-in functions (len, max, and min) operate on strings as
they do on lists and tuples. Index and slice notation works the same for obtaining elements or slices but
can’t be used to add, remove, or replace elements.

Strings support many methods - capitalize, center, count, decode, encode, endswith, expandtabs, find,
format, index, isalnum, isalpha, isdigit, islower, isspace, istitle, isupper, join, ljust, lower, lstrip, partition,
replace, rfind, rindex, rjust, rpartition, rsplit, rstrip, split, splitlines, startswith, strip, swapcase, title, translate,
upper, zfill. Although these methods operate on string instances, none of these methods actually modifies
the underlying string data. Thus, methods such as s.capitalize(), s.center(), and s.expandtabs() always return
a new string as opposed to modifying the string s. Character tests such as s.isalnum() and s.isupper() return
True or False if all the characters in the string s satisfy the test. Furthermore, these tests always return False
if the length of the string is zero.

The s.find(), s.index(), s.rfind(), and s.rindex() methods are used to search s for a substring. All these
functions return an integer index to the substring in s. In addition, the find() method returns -1 if the substring
isn’t found, whereas the index() method raises a ValueError exception. The s.replace() method is used to
replace a substring with replacement text. It is important to emphasize that all of these methods only work
with simple substrings. Regular expression pattern matching and searching is handled by functions in the re
library module.

The s.split() and s.rsplit() methods split a string into a list of fields separated by a delimiter. The s.partition()
and s.rpartition() methods search for a separator substring and partition s into three parts corresponding to
text before the separator, the separator itself, and text after the separator.

Many of the string methods accept optional start and end parameters, which are integer values specifying
the starting and ending indices in s. In most cases, these values may be given negative values, in which
case the index is taken from the end of the string.

The s.format() method is used to perform string formatting. As arguments, it accepts any combination of
positional and keyword arguments. Placeholders in s denot- ed by {item} are replaced by the appropriate
argument. Positional arguments can be referenced using placeholders such as {0} and {1}. Keyword
arguments are referenced using a placeholder with a name such as {name}. Here is an example:

In [64]:

a = "Your name is {0} and your age is {age}"


a.format("Mike", age=40)

Out[64]:

'Your name is Mike and your age is 40'

file:///Users/adityasingh/Downloads/Main.html 18/39
6/17/2019 Main

file:///Users/adityasingh/Downloads/Main.html 19/39
6/17/2019 Main

file:///Users/adityasingh/Downloads/Main.html 20/39
6/17/2019 Main

To loop over characters in a string , use the in keyword just like a list "in" can also be used to check
substring

In [20]:

x = "the quick brown fox jumps over the lazy dog"


x.split()

Out[20]:

['the', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'do


g']

In [3]:

# find the index of a "c" in a string "abcde"


"abcde".index("c")

Out[3]:

In [97]:

y = "sdsdgfgdfgdf_sdfsdfsdf"
y.split('_')

Out[97]:

['sdsdgfgdfgdf', 'sdfsdfsdf']

In [98]:

#Returns a new string


y.replace('df','*')

Out[98]:

'sdsdgfg*g*_s*s*s*'

In [100]:

y[3]

Out[100]:

'd'

In [102]:

#Will throw exception because strings are immutable


#y[3]="k"

The [ ] syntax and the len() function actually work on any sequence type -- strings, lists, etc..

file:///Users/adityasingh/Downloads/Main.html 21/39
6/17/2019 Main

Other Common String Methods

Check for substrings

In [7]:

a = "jdfksjdfiwjriwejrsdkf"
"fiw" in a

Out[7]:

True

Strings are stored as sequences of characters indexed by integers, starting at zero.To extract a single
character, use the indexing operator s[i] like this:

In [32]:

a = "Hello World"
b = a[4] # b = 'o'

To extract a substring, use the slicing operator s[i:j].This extracts all characters from s whose index k is in the
range i <= k < j. If either index is omitted, the beginning or end of the string is assumed, respectively:

In [34]:

c = a[:5]
d = a[6:]
e = a[3:8]
# c = "Hello" # d = "World" # e = "lo Wo"

Strings are concatenated with the plus (+) operator:

Python never implicitly interprets the contents of a string as numerical data (i.e., as in other languages such
as Perl or PHP). For example, + always concatenates strings:

To perform mathematical calculations, strings first have to be converted into a numeric value using a
function such as int() or float(). For example:

In [36]:

g = a + " This is a test"

x = "37"
y = "42"
z = x + y # z = "3742" (String Concatenation)

z = int(x) + int(y) # z = 79 (Integer +)

Non-string values can be converted into a string representation by using the str(), repr(), or format() function.

file:///Users/adityasingh/Downloads/Main.html 22/39
6/17/2019 Main

In [ ]:

s = "The value of x is " + str(x)


s = "The value of x is " + repr(x)
s = "The value of x is " + format(x,"4d")

In [55]:

k =" sdfAAFSERfdsf "


print(k.lower())
print(k.upper())
print(k.strip())
print(k.lstrip())
print(k)

sdfaafserfdsf
SDFAAFSERFDSF
sdfAAFSERfdsf
sdfAAFSERfdsf
sdfAAFSERfdsf

In [67]:

print(" ".isspace())
print("abc".isalpha())
print("hello ".islower())
print("helLo ".islower())
print("helLo ".isupper())
print("HELLO".isupper())

True
True
True
False
False
True

In [26]:

m = "323432"
m.isdigit()

Out[26]:

True

In [27]:

print(m.startswith("32"))
print(m.endswith("32"))

True
True

file:///Users/adityasingh/Downloads/Main.html 23/39
6/17/2019 Main

In [28]:

a = "334Aditya34_"
print(a.find("42"))
print(a.find("Aditya"))
print(a.replace("Aditya","Singh"))

-1
3
334Singh34_

In [29]:

k = ["Aditya","Singh","Hello","World"]
g = "_"
g.join(k)

Out[29]:

'Aditya_Singh_Hello_World'

In [30]:

"_".join(["a","b"])

Out[30]:

'a_b'

In [31]:

k="fjfhshellosuweyriwriehellodfkdfkhello"
k.count("hello")

Out[31]:

In [32]:

k.index("hello")

Out[32]:

In [33]:

print(k.find("hello"))
print(k.find("world"))

5
-1

In [34]:

list("hello, world")

Out[34]:

['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']

file:///Users/adityasingh/Downloads/Main.html 24/39
6/17/2019 Main

In [69]:

k = list("Aditya")
k.reverse()
print("".join(k))

aytidA

In [71]:

"{0} is the {1} of {2}".format("Ambrosia", "food", "the gods")

Out[71]:

'Ambrosia is the food of the gods'

In [6]:

#printf style formatting


"%s is the %s of %s" % ("Ambrosia", "food", "the gods")

Out[6]:

'Ambrosia is the food of the gods'

Tuples
Tuples are like lists that can’t be modified—you can think of them as a restricted type of list or as a basic
record type. Tuples are immutable To create a tuple, just list the values within parenthesis separated by
commas. The "empty" tuple is just an empty pair of parenthesis. Accessing the elements in a tuple is just
like a list -- len(), [ ], for, in, etc. all work the same. Although tuples support most of the same operations as
lists (such as indexing, slicing, and concatenation), the contents of a tuple cannot be modified after creation
(that is, you cannot replace, delete, or append new elements to an existing tuple).This reflects the fact that a
tuple is best viewed as a single object consisting of several parts, not as a collection of distinct objects to
which you might insert or remove items. Because there is so much overlap between tuples and lists, some
programmers are inclined to ignore tuples altogether and simply use lists because they seem to be more
flexible. Although this works, it wastes memory if your program is going to create a large number of small
lists (that is, each containing fewer than a dozen items).This is because lists slightly overallocate memory to
optimize the performance of operations that add new items. Because tuples are immutable, they use a more
compact representation where there is no extra space.

To create a size-1 tuple, the lone element must be followed by a comma.

Tuples and lists are often used together to represent data. For example, this program shows how you might
read a file consisting of different columns of data separated by commas. The split() method of strings splits a
string into a list of fields separated by the given delimiter character.The resulting portfolio data structure
created by this program looks like a two-dimension array of rows and columns. Each row is represented by a
tuple and can be accessed as follows:

file:///Users/adityasingh/Downloads/Main.html 25/39
6/17/2019 Main

In [ ]:

# File containing lines of the form "name,shares,price"


filename = "portfolio.csv"
portfolio = []
for line in open(filename):
fields = line.split(",")
name = fields[0]
shares = int(fields[1])
price = float(fields[2])
stock = (name,shares,price)
portfolio.append(stock)
#portfolio[0]
#('GOOG', 100, 490.10)

#Here’s an easy way to loop over all of the records and expand fields into a set
of variables:

total = 0.0
for name, shares, price in portfolio:
total += shares * price

In [36]:

t = (1, 2, 'hi')
print(len(t))
print(t[2])
t = (1, 2, 'bye')

#This will throw an error


#tuple[2] = 'bye'

3
hi

In [37]:

(x,y,z) = ("Hello","World","Python")
print(x)
print(type(x))

#Works for lists too


[a,b,c]=["Hello","World","Python"]
print(b)
print(type(b))

#If they are not of the same size, it will throw an error

Hello
<class 'str'>
World
<class 'str'>

file:///Users/adityasingh/Downloads/Main.html 26/39
6/17/2019 Main

In [38]:

#Swapping variables
var1 = 3
var2 = 2
var1, var2 = var2, var1
print(var1, var2)

2 3

In [39]:

#Creating a list from a tuple and tuple from a list


print(list((1, 2, 3, 4)))
print(tuple([1, 2, 3, 4]))

[1, 2, 3, 4]
(1, 2, 3, 4)

file:///Users/adityasingh/Downloads/Main.html 27/39
6/17/2019 Main

Packing & Unpacking


To make things even more convenient, Python 3 has an extended unpacking feature, allowing an element
marked with a * to absorb any number elements not matching the other elements. Again, some examples
will make this clearer:

--> x = (1, 2, 3, 4)
--> a, b, c = x
--> a, b, c
(1, 2, [3, 4])
--> a, b, c = x
--> a, b, c
(1, [2, 3], 4)
--> a, b, c = x
--> a, b, c
([1, 2], 3, 4)
--> a, b, c, d, e = x
--> a, b, c, d, e
(1, 2, 3, 4, [])

Note that the starred element receives all the surplus items as a list, and that if there are no surplus
elements, it receives an empty list.

Packing and unpacking can be performed using list delimiters as well:

--> [a, b] = [1, 2]


--> [c, d] = 3, 4
--> [e, f] = (5, 6)
--> (g, h) = 7, 8
--> i, j = [9, 10]
--> k, l = (11, 12)
--> a
1
--> [b, c, d]
[2, 3, 4]
--> (e, f, g)
(5, 6, 7)
--> h, i, j, k, l
(8, 9, 10, 11, 12)

file:///Users/adityasingh/Downloads/Main.html 28/39
6/17/2019 Main

In [13]:

# A sample function that takes 4 arguments


# and prints the,
def fun(a, b, c, d):
print(a, b, c, d)

# Driver Code
my_list = [1, 2, 3, 4]

# Unpacking list into four arguments


fun(*my_list)

1 2 3 4

In [14]:

# A Python program to demonstrate use


# of packing

# This function uses packing to sum


# unknown number of arguments
def mySum(*args):
sum = 0
for i in range(0, len(args)):
sum = sum + args[i]
return sum

# Driver code
print(mySum(1, 2, 3, 4, 5))
print(mySum(10, 20))

15
30

List Comprehensions
The syntax is [ expr for var in list ] -- the for var in list looks like a regular for-loop, but without the colon (:).
The expr to its left is evaluated once for each element to give the values for the new list. Here is an example
with strings, where each string is changed to upper case with '!!!' appended:

new_list = [expression for variable in old_list if expression]

In [ ]:

# Convert all of the input values from strings to floats


fvalues = [float(line) for line in lines]

In [40]:

nums = [1, 2, 3, 4]
squares = [ n * n for n in nums ]
print(squares)

[1, 4, 9, 16]

file:///Users/adityasingh/Downloads/Main.html 29/39
6/17/2019 Main

In [41]:

strs = ['hello', 'and', 'goodbye']


shouting = [ s.upper() + '!!!' for s in strs ]
print(shouting)

['HELLO!!!', 'AND!!!', 'GOODBYE!!!']

You can add an if test to the right of the for-loop to narrow the result. The if test is evaluated for each
element, including only the elements where the test is true.

In [42]:

nums = [2, 8, 1, 6]
small = [ n for n in nums if n <= 2 ]
print(small)

[2, 1]

file:///Users/adityasingh/Downloads/Main.html 30/39
6/17/2019 Main

Dictionaries
A dictionary is an associative array or hash table that contains objects indexed by keys. Strings, numbers,
and tuples work as keys, and any type can be a value. Other types may or may not work correctly as keys
(strings and tuples work cleanly since they are immutable). Looking up a value which is not in the dict throws
a KeyError -- use "in" to check if the key is in the dict, or use dict.get(key) which returns the value or None if
the key is not present (or get(key, not-found) allows you to specify what value to return in the not-found
case).

Most of the methods in table are used to manipulate or retrieve the contents of a dictionary.The m.clear()
method removes all items.The m.update(b) method updates the current mapping object by inserting all the
(key,value) pairs found in the mapping object b.The m.get(k [,v]) method retrieves an object but allows for an
optional default value,v, that’s returned if no such key exists.The m.setdefault(k [,v]) method is similar to
m.get(), except that in addition to returning v if no object exists, it sets m[k] = v. If v is omitted, it defaults to
None. The m.pop() method returns an item from a dictionary and removes it at the same time. The
m.popitem() method is used to iteratively destroy the contents of a dictionary.

The m.copy() method makes a shallow copy of the items contained in a mapping object and places them in
a new mapping object. The m.fromkeys(s [,value]) method creates a new mapping with keys all taken from a
sequence s. The type of the resulting mapping will be the same as m. The value associated with all of these
keys is set to None unless an alternative value is given with the optional value parameter.The fromkeys()
method is defined as a class method, so an alternative way to invoke it would be to use the class name such
as dict.fromkeys().

The m.items() method returns a sequence containing (key,value) pairs.The m.keys() method returns a
sequence with all the key values, and the m.values() method returns a sequence with all the values. For
these methods, you should assume that the only safe operation that can be performed on the result is
iteration. In Python 2 the result is a list, but in Python 3 the result is an iterator that iterates over the current
file:///Users/adityasingh/Downloads/Main.html 31/39
6/17/2019 Main

contents of the mapping. If you write code that simply assumes it is an iterator, it will be generally
compatible with both versions of Python. If you need to store the result of these methods as data, make a
copy by storing it in a list. For example, items = list(m.items()). If you simply want a list of all keys, use keys =
list(m).

In [53]:

mydict = {}
mydict = dict()
print(type(mydict))

mydict = {"hello":2, "world":1}


print(mydict["hello"])

mynewdict = {2:"hello",3:"world"}
print(mynewdict[2])

<class 'dict'>
2
hello

Dictionary membership is tested with the in operator, as in the following example:

In [54]:

prices = {
"GOOG" : 490.10,
"AAPL" : 123.50,
"IBM" : 91.50,
"MSFT" : 52.13
}

if "SCOX" in prices:
p = prices["SCOX"]
else:
p = 0.0

#This particular sequence of steps can also be performed more compactly as follo
ws:
#p = prices.get("SCOX",0.0)

print(p)

0.0

In [57]:

mynewdict[2]="aditya"
print(mynewdict)

{2: 'aditya', 3: 'world'}

file:///Users/adityasingh/Downloads/Main.html 32/39
6/17/2019 Main

In [58]:

mynewdict.keys()

Out[58]:

dict_keys([2, 3])

In [59]:

#To obtain a list of dictionary keys, convert a dictionary to a list:


syms = list(mynewdict)
print(syms)

[2, 3]

In [46]:

mynewdict.values()

Out[46]:

dict_values(['aditya', 'world'])

Use the del statement to remove an element of a dictionary:

del prices["MSFT"]

In [81]:

#items() returns a iterable which returns a list of key-value tuples


for item in mynewdict.items():
print(item)

(2, 'hello')
(3, 'world')

In [82]:

list(mynewdict.items())

Out[82]:

[(2, 'hello'), (3, 'world')]

Note: iteritems() has been removed from the python 3.x it only works in python 2.x.Instead use dict.items().

Using iteritem(): iteritems() is used to loop through the dictionary printing the dictionary key-value pair
sequentially.

Using items(): items() performs the similar task on dictionary as iteritems() but have certain disadvantages
when compared with iteritems(). It is very time consuming. Calling it on large dictionaries consumes quite a
lot of time. It takes a lot of memory. Sometimes takes double the memory when called on dictionary.

file:///Users/adityasingh/Downloads/Main.html 33/39
6/17/2019 Main

In [83]:

testdict = {}
testdict[3] = "hello"
testdict[4] = "world"
print(testdict)

{3: 'hello', 4: 'world'}

In [85]:

#you can test the dictionary for the presence of a key with the in keyword
3 in testdict

Out[85]:

True

In [87]:

testdict.get(5, "No such key in dictionary")

Out[87]:

'No such key in dictionary'

In [90]:

#Similarly, if you want to safely get a key’s value and make sure it’s set to a
default
#in the dictionary, you can use the setdefault method:
print(testdict.setdefault(5, 'No translation'))

No translation

In [92]:

print(testdict)

{3: 'hello', 4: 'world', 5: 'No translation'}

You can obtain a copy of a dictionary using the copy method. This makes a shallow copy of the dictionary.
This will likely be all you need in most situations. For dictionaries that contain any modifiable objects as
values (that is, lists or other dictionaries), you may want to make a deep copy using the copy.deepcopy
function.

In [94]:

#The update method updates a first dictionary with all the key/value pairs of a
second dictionary.
#For keys that are common to both, the values from the second dictionary overrid
e those of the first:
z = {1: 'One', 2: 'Two'}
x = {0: 'zero', 1: 'one'}
x.update(z)
print(x)

{0: 'zero', 1: 'One', 2: 'Two'}

file:///Users/adityasingh/Downloads/Main.html 34/39
6/17/2019 Main

In [103]:

#Count the number of times every word occurs in a string


sample_string = "To be or not to be"
occurrences = {}
for word in sample_string.split():
occurrences[word] = occurrences.get(word, 0) + 1
for word in occurrences:
print("The word", word, "occurs", occurrences[word], "times in the string")

The word To occurs 1 times in the string


The word be occurs 2 times in the string
The word or occurs 1 times in the string
The word not occurs 1 times in the string
The word to occurs 1 times in the string

Any Python object that is immutable and hashable can be used as a key to a dictionary.Unfortunately, the
requirement that keys be immutable and hashable means that lists can’t be used as dictionary keys. But
there are many instances when it would be convenient to have a listlike key. Python solves this difficulty by
providing tuples, which are basically immutable lists—they’re created and used similar to lists, except that
when you have them, you can’t modify them. But there’s one further restriction: keys must also be hashable,
which takes things a step further than just immutable. To be hashable, a value must have a hash value
(provided by a hash method) that never changes throughout the life of the value. That means that tuples
containing mutable values, although they themselves are immutable, aren’t hashable. Only tuples that don’t
contain any mutable objects nested within them are hashable and valid to use as keys for dictionaries.

file:///Users/adityasingh/Downloads/Main.html 35/39
6/17/2019 Main

In [109]:

mydict = {}
mydict[("a","b")] = 4

# TypeError: unhashable type: 'list'


# mydict[("b",[1,2])] = 4

print(mydict)

{('a', 'b'): 4}

You can also use the get method to retrieve the values in a dict. The only difference is that in the get method,
you can set a default value. In direct referencing, if the key is not present, the interpreter throws KeyError.

print(alphabets.get(1)) print(alphabets.get(2, "default"))

**Looping over a dictionary items

for key, value in person1_information.items():

In [6]:

#Delete items from a dictionary

#initialise a dictionary with the keys “city”, “name”, “food”

person1_information = {'city': 'San Francisco', 'name': 'Sam', "food": "shrimps"


}
del person1_information["food"]

A disadvantage is that it gives KeyError if you try to delete a nonexistent key. So, instead of the del
statement you can use the pop method. This method takes in the key as the parameter. As a second
argument, you can pass the default value if the key is not present.

print(person1_information.pop("food", None))

You can test the presence of a key using the has_key method.

A dictionary in Python doesn't preserve the order.

Dictionary comprehension
new_dict = {expression:expression for variable in list if expression}

file:///Users/adityasingh/Downloads/Main.html 36/39
6/17/2019 Main

Sets
https://www.hackerearth.com/practice/python/working-with-data/set/tutorial/
(https://www.hackerearth.com/practice/python/working-with-data/set/tutorial/)

A set in Python is an unordered collection of objects used in situations where membership and uniqueness
in the set are main things you need to know about that object. Just as with dictionary keys, the items in a set
must be immutable and hashable. This means that ints, floats, strings, and tuples can be members of a set,
but lists, dictionaries, and sets themselves can’t. Unlike sequences, sets provide no indexing or slicing
operations.They are also unlike dictionaries in that there are no key values associated with the objects.The
items placed into a set must be immutable.Two different set types are available: set is a mutable set, and
frozenset is an immutable set. Both set() and frozenset() populate the set by iterating over the supplied
argument. The s.difference(t), s.intersection(t), s.symmetric_difference(t), and s.union(t) methods provide the
standard mathematical operations on sets.The returned value has the same type as s (set or frozenset).The
parameter t can be any Python object that supports iteration.This includes sets, lists, tuples, and strings.

In addition to the operations that apply to collections in general, like in, len, and being able to use a for loop
to iterate over all of their elements, sets also have several set-specific operations:

Sets support a standard collection of operations, including union, intersection, difference, and symmetric
difference. Here’s an example:

a = t | s #Union of t and s
b = t & s #Intersection of t and s
c = t – s #Set difference (items in t, but not in s)
d = t ^ s #Symmetric difference (items in t or s, but not both)

In [2]:

myset = {4,6,7,7,7,8}

In [3]:

myset

Out[3]:

{4, 6, 7, 8}

file:///Users/adityasingh/Downloads/Main.html 37/39
6/17/2019 Main

In [5]:

print(type(myset))

<class 'set'>

In [49]:

#When a sequence is made into a set, duplicates are removed


x = set([4,4,7,3,5,8])
print(x)
print(type(x))

{3, 4, 5, 7, 8}
<class 'set'>

In [52]:

x.add("hello")
x.update(["world","aditya"])
x.remove("aditya")
print(x)
x.remove(7)
print(x)
print(1 in x)
print(4 in x)

{3, 4, 5, 7, 8, 'world', 'hello'}


{3, 4, 5, 8, 'world', 'hello'}
False
True

In [50]:

x = set([3,4,5,6])
y = set([6,7,8,9])

#Set Union
print(x | y)

#Set Intersection
print(x & y)

# Symmetric difference—that is, elements that are in one set or the other but no
t both.
print(x ^ y)

{3, 4, 5, 6, 7, 8, 9}
{6}
{3, 4, 5, 7, 8, 9}

Frozensets
Because sets aren’t immutable and hashable, they can’t belong to other sets. To remedy that situation there
is another set type, frozenset, which is just like a set but can’t be changed after creation. Because frozensets
are immutable and hashable, they can be members of other sets:

file:///Users/adityasingh/Downloads/Main.html 38/39
6/17/2019 Main

In [51]:

z = frozenset([3,4,5,6])
print(z)

frozenset({3, 4, 5, 6})

In [52]:

#Will throw exceptions because they are immutable


#z.add(8)
#z.remove(4)

file:///Users/adityasingh/Downloads/Main.html 39/39
6/17/2019 Control Flow

While loop
while condition:
    body
else:
    post-code

condition is an expression that evaluates to a true or false value. As long as it’s True, the body will be
executed repeatedly. If it evaluates to False, the while loop will execute the post-code section and then
terminate. If the condition starts out by being false, the body won’t be executed at all—just the post-code
section. The two special statements break and continue can be used in the body of a while loop. If break is
executed, it immediately terminates the while loop, and not even the post-code (if there is an else clause) will
be executed. If continue is executed, it causes the remainder of the body to be skipped over; the condition
is evaluated again, and the loop proceeds as normal.

If - elif - else
There is no case (or switch) statement in Python.

if condition1:
    body1
elif condition2:
    body2
elif condition3:
    body3
.
.
.
elif condition(n-1):
    body(n-1)
else:
    body(n)

It says: if condition1 is true, execute body1; otherwise, if condition2 is true, execute body2; otherwise … and
so on, until it either finds a condition that evaluates to True or hits the else clause, in which case it executes
body(n). Of course, you don’t need all that luggage for every conditional. You can leave out the elif parts, or
the else part, or both. If a conditional can’t find any body to execute (no conditions evaluate to True, and
there is no else part), it does nothing.

file:///Users/adityasingh/Downloads/Control Flow.html 1/10


6/17/2019 Control Flow

In [2]:

# Python program to illustrate


# selection statement

num1 = 34
if(num1>12):
print("Num1 is good")
elif(num1>35):
print("Num2 is not gooooo....")
else:
print("Num2 is great")

Num1 is good

For loop
A for loop in Python is different from for loops in some other languages. The traditional pattern is to
increment and test a variable on each iteration, which is what C for loops usually do. In Python, a for loop
iterates over the values returned by any iterable object—that is, any object that can yield a sequence of
values. For example, a for loop can iterate over every element in a list, a tuple, or a string. But an iterable
object can also be a special function called range or a special type of function called a generator. This can
be quite powerful. The for loop is one of Python’s most powerful language features because you can create
custom iterator objects and generator functions that supply it with sequences of values. The general form is

for item in sequence:


    body
else:
    post-code

The else part is optional. As with the else part of a while loop, it’s rarely used. break and continue do the
same thing in a for loop as in a while loop.

In [2]:

for n in [1,2,3,4,5,6,7,8,9]:
print("2 to the %d power is %d" % (n, 2**n))

2 to the 1 power is 2
2 to the 2 power is 4
2 to the 3 power is 8
2 to the 4 power is 16
2 to the 5 power is 32
2 to the 6 power is 64
2 to the 7 power is 128
2 to the 8 power is 256
2 to the 9 power is 512

file:///Users/adityasingh/Downloads/Control Flow.html 2/10


6/17/2019 Control Flow

Iterators
Iterator in python is any python type that can be used with a ‘for in loop’. Python lists, tuples, dicts and sets
are all examples of inbuilt iterators. These types are iterators because they implement following methods. In
fact, any object that wants to be an iterator must implement following methods.

iter method that is called on initialization of an iterator. This should return an object that has a next or next
(in Python 3) method.
next ( next in Python 3) The iterator next method should return the next value for the iterable. When an
iterator is used with a ‘for in’ loop, the for loop implicitly calls next() on the iterator object. This method
should raise a StopIteration to signal the end of the iteration.

Alternative switch-case

Python doesn't have a switch case. But we can work around it this way using a dictionary

In [14]:

# Function to convert number into string. Switcher is dictionary data type here
def numbers_to_strings(argument):
switcher = {
0: "zero",
1: "one",
2: "two",
}

# get() method of dictionary data type returns


# value of passed argument if it is present
# in dictionary otherwise second argument will
# be assigned as default value of passed argument
return switcher.get(argument, "nothing")

# Driver program
if __name__ == "__main__":
argument=0
print(numbers_to_strings(argument))

zero

file:///Users/adityasingh/Downloads/Control Flow.html 3/10


6/17/2019 Control Flow

The range function


Given a number n, range(n) returns a sequence 0, 1, 2, …, n–2, n–1. So, passing it the length of a list (found
using len) produces a sequence of the indices for that list’s elements. The range function doesn’t build a
Python list of integers—it just appears to. Instead, it creates a range object that produces integers on
demand. This is useful when you’re using explicit loops to iterate over really large lists. Instead of building a
list with 10 million elements in it, for example, which would take up quite a bit of memory, you can use
range(10000000), which takes up only a small amount of memory and generates a sequence of integers
from 0 up to 10000000 as needed by the for loop. The for statement is not limited to sequences of integers
and can be used to iterate over many kinds of objects including strings, lists, dictionaries, and files.

Sequences returned by range always include the starting value given as an argument to range and never
include the ending value given as an argument.

You can use two variants on the range function to gain more control over the sequence it produces. If you
use range with two numeric arguments, the first argument is the starting number for the resulting sequence
and the second number is the number the resulting sequence goes up to (but doesn’t include).

range() and xrange() are two functions that could be used to iterate a certain number of times in for loops in
Python. In Python 3, there is no xrange , but the range function behaves like xrange in Python 2.If you want
to write code that will run on both Python 2 and Python 3, you should use range(). The built-in function
xrange([i,]j [,stride]) creates an object that represents a range of integers k such that i <= k < j. The first index,
i, and the stride are optional and have default values of 0 and 1, respectively. An xrange object calculates its
values whenever it’s accessed and although an xrange object looks like a sequence, it is actually somewhat
limited. For example, none of the standard slicing operations are supported. This limits the utility of xrange
to only a few applications such as iterating in simple loops. It should be noted that in Python 3, xrange() has
been renamed to range(). However, it operates in exactly the same manner as described here.

range() – This returns a list of numbers created using range() function.


xrange() – This function returns the generator object that can be used to display numbers only by looping.
Only particular range is displayed on demand and hence called “lazy evaluation“.

In [5]:

for n in range(1,10):
print("2 to the %d power is %d" % (n, 2**n))

2 to the 1 power is 2
2 to the 2 power is 4
2 to the 3 power is 8
2 to the 4 power is 16
2 to the 5 power is 32
2 to the 6 power is 64
2 to the 7 power is 128
2 to the 8 power is 256
2 to the 9 power is 512

file:///Users/adityasingh/Downloads/Control Flow.html 4/10


6/17/2019 Control Flow

In [3]:

print(list(range(3, 7)))
print(list(range(2, 10)))
print(list(range(5, 3)))

[3, 4, 5, 6]
[2, 3, 4, 5, 6, 7, 8, 9]
[]

The range(i,j [,stride]) function creates an object that represents a range of inte- gers with values i to j-1. If
the starting value is omitted, it’s taken to be zero. An optional stride can also be given as a third argument.

This still doesn’t allow you to count backward, which is why the value of range(5, 3) is an empty list. To count
backward, or to count by any amount other than 1, you need to use the optional third argument to range,
which gives a step value by which counting proceeds:

In [4]:

print(list(range(0, 10, 2)))


print(list(range(5, 0, -1)))

[0, 2, 4, 6, 8]
[5, 4, 3, 2, 1]

In [6]:

#Tuple unpacking
somelist = [(1, 2), (3, 7), (9, 5)]
result = 0
for x, y in somelist:
result = result + (x * y)
print(result)

68

One caution with range() is that in Python 2, the value it creates is a fully populated list with all of the integer
values. For extremely large ranges, this can inadvertently consume all available memory.Therefore, in older
Python code, you will see programmers using an alternative function xrange(). The object created by
xrange() computes the values it represents on demand when lookups are requested. For this reason, it is the
preferred way to represent extremely large ranges of integer values. In Python 3, the xrange() function has
been renamed to range() and the functionality of the old range() function has been removed.

Enumerate function
You can combine tuple unpacking with the enumerate function to loop over both the items and their index.

Using enumerate(): enumerate() is used to loop through the containers printing the index number along with
the value present in that particular index. Enumerate is built-in python function that takes input as iterator,
list etc and returns a tuple containing index and data at that index in the iterator sequence. For example,
enumerate(cars), returns a iterator that will return (0, cars[0]), (1, cars[1]), (2, cars[2]), and so on.

file:///Users/adityasingh/Downloads/Control Flow.html 5/10


6/17/2019 Control Flow

In [7]:

x = [1, 3, -7, 4, 9, -5, 4]


for i, n in enumerate(x):
if n < 0:
print("Found a negative number at index ", i)

Found a negative number at index 2


Found a negative number at index 5

In [7]:

# python code to demonstrate working of enumerate()

for key, value in enumerate(['The', 'Big', 'Bang', 'Theory']):


print(key, value)

0 The
1 Big
2 Bang
3 Theory

In [8]:

# Accessing items and indexes enumerate()

cars = ["Aston" , "Audi", "McLaren "]


for x in enumerate(cars):
print (x[0], x[1])

0 Aston
1 Audi
2 McLaren

In [10]:

# Printing return value of enumerate()

cars = ["Aston" , "Audi", "McLaren "]


print(enumerate(cars))

<enumerate object at 0x10f30a900>

In [11]:

# demonstrating the use of start in enumerate

cars = ["Aston" , "Audi", "McLaren "]


for x in enumerate(cars, start=1):
print (x[0], x[1])

1 Aston
2 Audi
3 McLaren

file:///Users/adityasingh/Downloads/Control Flow.html 6/10


6/17/2019 Control Flow

Zip function
Sometimes it’s useful to combine two or more iterables before looping over them. The zip function will take
the corresponding elements from one or more iterables and combine them into tuples until it reaches the
end of the shortest iterable :

In [8]:

x = [1, 2, 3, 4]
y = ['a', 'b', 'c']
z = zip(x, y)
list(z)

Out[8]:

[(1, 'a'), (2, 'b'), (3, 'c')]

Using zip(): zip() is used to combine 2 similar containers(list-list or dict-dict) printing the values sequentially.
The loop exists only till the smaller container ends.

In [6]:

# python code to demonstrate working of zip()

# initializing list
questions = ['name', 'colour', 'shape']
answers = ['apple', 'red', 'a circle']

# using zip() to combine two containers


# and print values
for question, answer in zip(questions, answers):
print('What is your {0}? I am {1}.'.format(question, answer))

What is your name? I am apple.


What is your colour? I am red.
What is your shape? I am a circle.

file:///Users/adityasingh/Downloads/Control Flow.html 7/10


6/17/2019 Control Flow

Truthiness, Falsiness And Relational Operators


In addition, Python is similar to C with respect to Boolean values, in that C uses the integer 0 to mean false
and any other integer to mean true. Python generalizes this idea; 0 or empty values are False, and any other
values are True. In practical terms, this means the following:

  The numbers 0, 0.0, and 0+0j are all False; any other number is True.
  The empty string "" is False; any other string is True.
  The empty list [] is False; any other list is True.
  The empty dictionary {} is False; any other dictionary is True.
  The empty set set() is False; any other set is True.
  The special Python value None is always False.
You can compare objects using normal operators: <, <=, >, >=, and so forth. == is the equality test operator,
and either != or <> may be used as the “not equal to” test. There are also in and not in operators to test
membership in sequences (lists, tuples, strings, and dictionaries) as well as is and is not operators to test
whether two objects are the same. Expressions that return a Boolean value may be combined into more
complex expressions using the and, or, and not operators.

In [10]:

#The and operator returns either the first false object (that an expression eval
uates to) or the last object.
[2] and [3,4]

Out[10]:

[3, 4]

In [11]:

[] and 5

Out[11]:

[]

In [12]:

#Similarly, the or operator returns either the first true object or the last obj
ect.
[2] or [3, 4]

Out[12]:

[2]

As with many other languages, evaluation stops as soon as a true expression is found for the or operator or
as soon as a false expression is found for the and operator.

The == and!= operators test to see if their operands contains the same values. They are used in most
situations. The is and is not operators test to see if their operands are the same object.

You also can invoke functions by using keyword arguments and supplying the argu- ments in arbitrary order.
However, this requires you to know the names of the argu- ments in the function definition.

file:///Users/adityasingh/Downloads/Control Flow.html 8/10


6/17/2019 Control Flow

Modules
In [10]:

# file : div.py
def divide(a,b):
q = a/b # If a and b are integers, q is an integer r = a - q*b
return (q,r)

To use your module in other programs, you can use the import statement:

In [ ]:

import div
a, b = div.divide(2305, 29)

The import statement creates a new namespace and executes all the statements in the associated .py file
within that namespace. To access the contents of the namespace after import, simply use the name of the
module as a prefix, as in div.divide() in the pre- ceding example. If you want to import a module using a
different name, supply the import statement with an optional as qualifier, as follows:

In [ ]:

import div as foo


a,b = foo.divide(2305,29)

As with objects, the dir() function lists the contents of a module and is a useful tool for interactive
experimentation:

file:///Users/adityasingh/Downloads/Control Flow.html 9/10


6/17/2019 Control Flow

In [13]:

import string
dir(string)

Out[13]:

['Formatter',
'Template',
'_ChainMap',
'_TemplateMetaclass',
'__all__',
'__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'_re',
'_string',
'ascii_letters',
'ascii_lowercase',
'ascii_uppercase',
'capwords',
'digits',
'hexdigits',
'octdigits',
'printable',
'punctuation',
'whitespace']

Since there is no main() function in Python, when the command to run a python program is given to the
interpreter, the code that is at level 0 indentation is to be executed. However, before doing that, it will define
a few special variables. name is one such special variable. If the source file is executed as the main
program, the interpreter sets the name variable to have a value “main”. If this file is being imported from
another module, name will be set to the module’s name. name is a built-in variable which evaluates to the
name of the current module. Thus it can be used to check whether the current script is being run on its own
or being imported somewhere else by combining it with if statement, as shown below.

In [4]:

# File1.py

print("File1 __name__ = %s" %__name__)

if __name__ == "__main__":
print("File1 is being run directly")
else:
print("File1 is being imported")

File1 __name__ = __main__


File1 is being run directly

In [ ]:

file:///Users/adityasingh/Downloads/Control Flow.html 10/10


6/17/2019 Functions

Functions are defined with the def statement. The order and number of arguments must match those given
in the function definition. If a mismatch exists, a TypeError exception is raised. When a function defines a
parameter with a default value, that parameter and all the parameters that follow are optional. If values are
not assigned to all the optional parameters in the function definition, a SyntaxError exception is raised.

Default parameter values are always set to the objects that were supplied as values when the function was
defined.

In [83]:

a = 10
def foo(x=a):
return x

a = 5 # Reassign 'a'.
foo()

Out[83]:

10

In addition, the use of mutable objects as default values may lead to unintended behavior

In [84]:

def foo(x, items=[]):


items.append(x)
return items

foo(1)
foo(2)
foo(3)

Out[84]:

[1, 2, 3]

Notice how the default argument retains modifications made from previous invocations. To prevent this, it is
better to use None and add a check as follows:

In [85]:

def foo(x, items=None):


if items is None:
items = []
items.append(x)
return items

file:///Users/adityasingh/Downloads/Functions.html 1/16
6/17/2019 Functions

A function can accept a variable number of parameters if an asterisk () is added to the last parameter name.
In this case, all the remaining arguments are placed into the args variable as a tuple. To pass a tuple args to a
function as if they were parameters, the args syntax can be used in a function call.

If the last argument of a function definition begins with **, all the additional keyword arguments (those that
don’t match any of the other parameter names) are placed in a dictionary and passed to the function.This
can be a useful way to write functions that accept a large number of potentially open-ended configuration
options that would be too unwieldy to list as parameters.

In [ ]:

def fprintf(file, fmt, *args):


file.write(fmt % args)

# Use fprintf. args gets (42,"hello world", 3.45)


fprintf(out,"%d %s %f", 42, "hello world", 3.45)

Function arguments can also be supplied by explicitly naming each parameter and spec- ifying a
value.These are known as keyword arguments.

def foo(w,x,y,z): statements

Keyword argument invocation

foo(x=3, y=22, w='hello', z=[1,2])

With keyword arguments, the order of the parameters doesn’t matter. However, unless there are default
values, you must explicitly name all of the required function parame- ters. If you omit any of the required
parameters or if the name of a keyword doesn’t match any of the parameter names in the function definition,
a TypeError exception is raised. Also, since any Python function can be called using the keyword calling
style, it is generally a good idea to define functions with descriptive argument names. Positional arguments
and keyword arguments can appear in the same function call, provided that all the positional arguments
appear first, values are provided for all non- optional arguments, and no argument value is defined more than
once. Here’s an example:

foo('hello', 3, z=[1,2], y=22)


foo(3, 22, w='hello', z=[1,2]) # TypeError. Multiple values for w

DEALING WITH AN INDEFINITE NUMBER OF POSITIONAL ARGUMENTS

Prefixing the final parameter name of the function with a * causes all excess nonkeyword arguments in a call
of a function (that is, those positional arguments not assigned to another parameter) to be collected together
and assigned as a tuple to the given parameter.

DEALING WITH AN INDEFINITE NUMBER OF ARGUMENTS PASSED BY KEYWORD

An arbitrary number of keyword arguments can also be handled. If the final parameter in the parameter list is
prefixed with , it will collect all excess keyword-passed arguments into a dictionary. The index for each entry
in the dictionary will be the keyword (parameter name) for the excess argument.

file:///Users/adityasingh/Downloads/Functions.html 2/16
6/17/2019 Functions

In [87]:

# Accept variable number of positional or keyword arguments


def spam(*args, **kwargs):
pass
# args is a tuple of positional args # kwargs is dictionary of keyword args

In [137]:

# A sample program to demonstrate unpacking of


# dictionary items using **
def fun(a, b, c):
print(a, b, c)

# A call with unpacking of dictionary


d = {'a':2, 'b':4, 'c':10}
fun(**d)

2 4 10

In [138]:

# A Python program to demonstrate packing of


# dictionary items using **
def fun(**kwargs):

# kwargs is a dict
print(type(kwargs))

# Printing dictionary items


for key in kwargs:
print("%s = %s" % (key, kwargs[key]))

# Driver code
fun(name="ubergeek", ID="101", language="Python")

<class 'dict'>
name = ubergeek
ID = 101
language = Python

Arguments are passed in by object reference. The parameter becomes a new reference to the object. For
immutable objects (such as tuples, strings, and numbers), what is done with a parameter has no effect
outside the function. But if you pass in a mutable object (for example, a list, dictionary, or class instance),
any change made to the object will change what the argument is referencing outside the function.

When a function is invoked, the function parameters are simply names that refer to the passed input
objects.The underlying semantics of parameter passing doesn’t neatly fit into any single style, such as “pass
by value” or “pass by reference,” that you might know about from other programming languages. For
example, if you pass an immutable value, the argument effectively looks like it was passed by value.
However, if a mutable object (such as a list or dictionary) is passed to a function where it’s then modified,
those changes will be reflected in the original object.

file:///Users/adityasingh/Downloads/Functions.html 3/16
6/17/2019 Functions

In [88]:

a = [1, 2, 3, 4, 5]
def square(items):
for i,x in enumerate(items):
items[i] = x * x # Modify items in-place

square(a) # Changes a to [1, 4, 9, 16, 25]


print(a)

[1, 4, 9, 16, 25]

Functions that mutate their input values or change the state of other parts of the pro- gram behind the
scenes like this are said to have side effects. As a general rule, this is a programming style that is best
avoided because such functions can become a source of subtle programming errors as programs grow in
size and complexity (for example, it’s not obvious from reading a function call if a function has side effects).
Such functions interact poorly with programs involving threads and concurrency because side effects
typically need to be protected by locks.

The return statement returns a value from a function. If no value is specified or you omit the return
statement, the None object is returned.To return multiple values, place them in a tuple.

Scoping
Each time a function executes, a new local namespace is created.This namespace repre- sents a local
environment that contains the names of the function parameters, as well as the names of variables that are
assigned inside the function body.When resolving names, the interpreter first searches the local namespace.
If no match exists, it searches the glob- al namespace.The global namespace for a function is always the
module in which the function was defined. If the interpreter finds no match in the global namespace, it
makes a final check in the built-in namespace. If this fails, a NameError exception is raised.

Inside a function, you can explicitly make a variable global by declaring it so before the variable is used,
using the global statement.

In [89]:

def fun():
global a
a = 1
b = 2

a = "one"
b = "two"
fun()
print(a,b)

1 two

Python 3 introduced the nonlocal keyword that allows you to assign to variables in an outer, but non-global,
scope. An example will illustrate what I mean.

file:///Users/adityasingh/Downloads/Functions.html 4/16
6/17/2019 Functions

In [90]:

def outside():
msg = "Outside!"
def inside():
msg = "Inside!"
print(msg)
inside()
print(msg)

outside()

Inside!
Outside!

In [91]:

def outside():
msg = "Outside!"
def inside():
nonlocal msg
msg = "Inside!"
print(msg)
inside()
print(msg)
outside()

Inside!
Inside!

Functions As Objects And Closures


Functions are first-class objects in Python.This means that they can be passed as argu- ments to other
functions, placed in data structures, and returned by a function as a result.

In [92]:

def callf(func):
func()

def helloworld():
print("Hello world!")

callf(helloworld)

Hello world!

When a function is handled as data, it implicitly carries information related to the surrounding environment
where the function was defined.This affects how free variables in the function are bound.

In [93]:

# foo.py
x = 42
def callf(func):
return func()

file:///Users/adityasingh/Downloads/Functions.html 5/16
6/17/2019 Functions

In [ ]:

import foo
x = 37

def helloworld():
print(x)

foo.callf(helloworld)
#Output - 37

In this example, notice how the function helloworld() uses the value of x that’s defined in the same
environment as where helloworld() was defined. Thus, even though there is also an x defined in foo.py and
that’s where helloworld() is actually being called, that value of x is not the one that’s used when helloworld()
executes. When the statements that make up a function are packaged together with the environment in
which they execute, the resulting object is known as a closure.The behavior of the previous example is
explained by the fact that all functions have a globals attribute that points to the global namespace in which
the function was defined.This always corresponds to the enclosing module in which a function was defined.

When nested functions are used, closures capture the entire environment needed for the inner function to
execute.

In [ ]:

import foo
def bar():
x = 13
def helloworld():
print(x)

foo.callf(helloworld)
##Output - 13

Closures and nested functions are especially useful if you want to write code based on the concept of lazy
or delayed evaluation.

In [96]:

from urllib.request import urlopen


def page(url):
def get():
return urlopen(url).read()
return get

In this example, the page() function doesn’t actually carry out any interesting computation. Instead, it merely
creates and returns a function get() that will fetch the contents of a web page when it is called.Thus, the
computation carried out in get() is actually delayed until some later point in a program when get() is
evaluated.

In [97]:

python = page("http://www.python.org")
jython = page("http://www.jython.org")

file:///Users/adityasingh/Downloads/Functions.html 6/16
6/17/2019 Functions

In [98]:

python

Out[98]:

<function __main__.page.<locals>.get()>

In [99]:

jython

Out[99]:

<function __main__.page.<locals>.get()>

In [100]:

#pydata = python()
#jydata = jython()

In this example, the two variables python and jython are actually two different versions of the get() function.
Even though the page() function that created these values is no longer executing, both get() functions
implicitly carry the values of the outer variables that were defined when the get() function was created. Thus,
when get() executes, it calls urlopen(url) with the value of url that was originally supplied to page(). With a
little inspection, you can view the contents of variables that are carried along in a closure.

In [101]:

python.__closure__

Out[101]:

(<cell at 0x10a1245e8: str object at 0x10a6f4150>,)

In [ ]:

python.__closure__[0].cell_contents

A closure can be a highly efficient way to preserve state across a series of function calls. For example,
consider this code that runs a simple counter

file:///Users/adityasingh/Downloads/Functions.html 7/16
6/17/2019 Functions

In [102]:

def countdown(n):
def next():
nonlocal n
r=n
n -= 1
return r
return next

# Example use
next = countdown(10)
while True:
v = next()
if not v:
break
else:
print(v)

10
9
8
7
6
5
4
3
2
1

In this code, a closure is being used to store the internal counter value n.The inner function next() updates
and returns the previous value of this counter variable each time it is called. Programmers not familiar with
closures might be inclined to implement similar functionality using a class such as this:

file:///Users/adityasingh/Downloads/Functions.html 8/16
6/17/2019 Functions

In [103]:

class Countdown(object):
def __init__(self,n):
self.n = n
def next(self):
r = self.n
self.n -= 1
return r

# Example use
c = Countdown(10)
while True:
v = c.next()
if not v:
break
else:
print(v)

10
9
8
7
6
5
4
3
2
1

However, if you increase the starting value of the countdown and perform a simple timing benchmark, you
will find that that the version using closures runs much faster (almost a 50% speedup). The fact that closures
capture the environment of inner functions also make them useful for applications where you want to wrap
existing functions in order to add extra capabilities.

A closure is a function that wraps around another function and some number of variables and "closes
over" or traps what it contains in its own scope.

In [141]:

def mult_closure(x):
def wrapped_func(y):
#wrapped_func closes over the x variable
return x*y
return wrapped_func

mult_by_three = mult_closure(3)
print(mult_by_three(5))

15

Decorators
A decorator is a function whose primary purpose is to wrap another function or class. The primary purpose
of this wrapping is to transparently alter or enhance the behavior of the object being wrapped.

file:///Users/adityasingh/Downloads/Functions.html 9/16
6/17/2019 Functions

In [ ]:

@trace
def square(x):
return x*x

The above is a short hand for the following

In [ ]:

def square(x):
return x*x
square = trace(square)

In the example, a function square() is defined. However, immediately after its definition, the function object
itself is passed to the function trace(), which returns an object that replaces the original square.

In [105]:

def decorate(func):
print("Decorating function: " + func.__name__)
def wrapper_func(*args):
print("Executing function: " + func.__name__)
return func(*args)
return wrapper_func

@decorate
def myfunction(param):
print(param)

myfunction("hello world")

Decorating function: myfunction


Executing function: myfunction
hello world

Generators & Coroutines


If a function uses the yield keyword, it defines an object known as a generator. A generator is a function that
produces a sequence of values for use in iteration. Here’s an example:

In [107]:

def countdown(n):
print("Counting down from %d" % n)
while n > 0:
yield n
n -= 1
return

If you call this function, you will find that none of its code starts executing. Instead, a generator object is
returned.The generator object, in turn, executes the func- tion whenever next() is called (or next() in Python
3)

file:///Users/adityasingh/Downloads/Functions.html 10/16
6/17/2019 Functions

In [108]:

k = countdown(10)

In [110]:

Out[110]:

<generator object countdown at 0x10a6b2a20>

In [109]:

k.__next__()

Counting down from 10

Out[109]:

10

In [111]:

k.__next__()

Out[111]:

In [112]:

k.__next__()

Out[112]:

When next() is invoked, the generator function executes statements until it reaches a yield statement. The
yield statement produces a result at which point execution of the function stops until next() is invoked again.
Execution then resumes with the statement following yield. You normally don’t call next() directly on a
generator but use it with the for statement, sum(), or some other operation that consumes a sequence.

In [113]:

for n in countdown(10):
pass
#statements

Counting down from 10

In [114]:

a = sum(countdown(10))

Counting down from 10

file:///Users/adityasingh/Downloads/Functions.html 11/16
6/17/2019 Functions

In [115]:

Out[115]:

55

A generator function signals completion by returning or raising StopIteration, at which point iteration stops. It
is never legal for a generator to return a value other than None upon completion. A subtle problem with
generators concerns the case where a generator function is only partially consumed. For example, consider
this code:

In [116]:

for n in countdown(10):
if n == 2:
break

Counting down from 10

In this example, the for loop aborts by calling break, and the associated generator never runs to full
completion.To handle this case, generator objects have a method close() that is used to signal a
shutdown.When a generator is no longer used or deleted, close() is called. Normally it is not necessary to
call close(), but you can also call it manually

In [117]:

def countdown(n):
print("Counting down from %d" % n)
try:
while n > 0:
yield n
n=n-1
except GeneratorExit:
print("Only made it to %d" % n)

Although it is possible to catch GeneratorExit, it is illegal for a generator function to handle the exception
and produce another output value using yield. Moreover, if a program is currently iterating on generator, you
should not call close() asynchronously on that generator from a separate thread of execution or from a signal
handler.

Inside a function, the yield statement can also be used as an expression that appears on the right side of an
assignment operator.

In [118]:

def receiver():
print("Ready to receive")
while True:
n = (yield)
print("Got %s" % n)

file:///Users/adityasingh/Downloads/Functions.html 12/16
6/17/2019 Functions

In [119]:

r = receiver()

In [120]:

r.__next__()

Ready to receive

In [121]:

r.send(3)

Got 3

In [122]:

r.send("Aditya")

Got Aditya

In [123]:

r.close()

In [125]:

r.send(8)

--------------------------------------------------------------------
-------
StopIteration Traceback (most recent cal
l last)
<ipython-input-125-e7372d3a5afb> in <module>
----> 1 r.send(8)

StopIteration:

In this example, the initial call to next() is necessary so that the coroutine executes statements leading to the
first yield expression. At this point, the coroutine suspends, waiting for a value to be sent to it using the
send() method of the associated generator object r.The value passed to send() is returned by the (yield)
expression in the coroutine. Upon receiving a value, a coroutine executes statements until the next yield
statement is encountered.

The requirement of first calling next() on a coroutine is easily overlooked and a common source of
errors.Therefore, it is recommended that coroutines be wrapped with a decorator that automatically takes
care of this step.

file:///Users/adityasingh/Downloads/Functions.html 13/16
6/17/2019 Functions

In [126]:

def coroutine(func):
def start(*args,**kwargs):
g = func(*args,**kwargs)
g.next()
return g
return start

@coroutine
def coroutinefunc():
pass

List Comprehensions
A common operation involving functions is that of applying a function to all of the items of a list, creating a
new list with the results.

In [127]:

nums = [1, 2, 3, 4, 5]
squares = []
for n in nums:
squares.append(n * n)
print(squares)

[1, 4, 9, 16, 25]

Because this type of operation is so common, it is has been turned into an operator known as a list
comprehension. Here is a simple example:

[expression for item1 in iterable1 if condition1]

In [128]:

nums = [1, 2, 3, 4, 5]
squares = [n * n for n in nums]

In [129]:

import math
f = [(1,2), (3,4), (5,6)]
g = [math.sqrt(x*x+y*y) for x,y in f]
print(g)

[2.23606797749979, 5.0, 7.810249675906654]

A generator expression is an object that carries out the same computation as a list comprehension, but
which iteratively produces the result.The syntax is the same as for list comprehensions except that you use
parentheses instead of square brackets. Unlike a list comprehension, a generator expression does not
actually create a list or immediately evaluate the expression inside the parentheses. Instead, it creates a
generator object that produces the values on demand via iteration.

file:///Users/adityasingh/Downloads/Functions.html 14/16
6/17/2019 Functions

In [130]:

a = [1,2,3,4]
b = (x*10 for x in a)
b.__next__()

Out[130]:

10

The difference between list and generator expressions is important, but subtle.With a list comprehension,
Python actually creates a list that contains the resulting data.With a generator expression, Python creates a
generator that merely knows how to produce data on demand.

Lambda Operator
Anonymous functions in the form of an expression can be created using the lambda.

lambda args:expression

In [131]:

mylamb = lambda x,y:(x*y)

In [132]:

mylamb

Out[132]:

<function __main__.<lambda>(x, y)>

In [133]:

mylamb(2,3)

Out[133]:

In [ ]:

names.sort(key=lambda n: n.lower())

Function Attributes
Functions can have arbitrary attributes attached to them. Function attributes are stored in a dictionary that is
available as the dict attribute

file:///Users/adityasingh/Downloads/Functions.html 15/16
6/17/2019 Functions

In [135]:

def foo():
pass

foo.secure = 1
foo.private = 1

In [136]:

foo.__dict__

Out[136]:

{'secure': 1, 'private': 1}

The primary use of function attributes is in highly specialized applications such as parser generators and
application frameworks that would like to attach additional infor- mation to function objects.

file:///Users/adityasingh/Downloads/Functions.html 16/16
6/17/2019 Classes & Objects

Classes & Objects


All values used in a program are objects.An object consists of internal data and methods that perform
various kinds of operations involving that data.You have already used objects and methods when working
with the built-in types such as strings and lists. For example:

In [2]:

items = [37, 42] # Create a list object


items.append(73) # Call the append() method

The dir() function lists the methods available on an object and is a useful tool for interactive experimentation.

file:///Users/adityasingh/Downloads/Classes & Objects.html 1/15


6/17/2019 Classes & Objects

In [3]:

dir(items)

Out[3]:

['__add__',
'__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__gt__',
'__hash__',
'__iadd__',
'__imul__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__rmul__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']

When inspecting objects, you will see familiar methods such as append() and insert() listed. However, you
will also see special methods that always begin and end with a double underscore.These methods
implement various language operations. For example, the add() method implements the + operator:

file:///Users/adityasingh/Downloads/Classes & Objects.html 2/15


6/17/2019 Classes & Objects

In [4]:

items.__add__([73,101])

Out[4]:

[37, 42, 73, 73, 101]

The class statement is used to define new types of objects and for object-oriented programming. For
example, the following class defines a simple stack with push(), pop(), and length() operations:

In [ ]:

class Stack(object):
def __init__(self):
self.stack = [ ]
def push(self,object):
self.stack.append(object)
def pop(self):
return self.stack.pop()
def length(self):
return len(self.stack)

In the first line of the class definition, the statement class Stack(object) declares Stack to be an object.The
use of parentheses is how Python specifies inheritance—in this case, Stack inherits from object, which is the
root of all Python types. Inside the class definition, methods are defined using the def statement.The first
argument in each method always refers to the object itself. By convention, self is the name used for this
argument.All operations involving the attributes of an object must explicitly refer to the self variable. Methods
with leading and trailing double underscores are special meth- ods. For example,init is used to initialize an
object after it’s created.

Normally, all of the methods defined within a class apply only to instances of that class (that is, the objects
that are created). However, different kinds of methods can be defined such as static methods familiar to C++
and Java programmers.

In [ ]:

class EventHandler(object):
@staticmethod #Decorator. Multiple decorators can be used on multiple lin
es
def dispatcherThread():
while (1):
# Wait for requests

The built-in function id() returns the identity of an object as an integer.This integer usually corresponds to the
object’s location in memory, although this is specific to the Python implementation and no such
interpretation of the identity should be made. The is operator compares the identity of two objects.The built-
in function type() returns the type of an object.

file:///Users/adityasingh/Downloads/Classes & Objects.html 3/15


6/17/2019 Classes & Objects

In [6]:

a = 42
print(id(a))
print(type(a))

4507806224
<class 'int'>

Comparing Objects

In [ ]:

# Compare two objects


def compare(a,b):
if a is b:
# a and b are the same object statements
if a == b:
# a and b have the same value statements
if type(a) is type(b):
# a and b have the same type statements

The type of an object is itself an object known as the object’s class.This object is uniquely defined and is
always the same for all instances of a given type.Therefore, the type can be compared using the is operator.
All type objects are assigned names that can be used to perform type checking. Most of these names are
built-ins, such as list, dict, and file.

In [ ]:

if type(s) is list:
s.append(item)

Because types can be specialized by defining classes, a better way to check types is to use the built-in
isinstance(object, type) function.

In [ ]:

if isinstance(s,list):
s.append(item)

Reference Counting And Garbage Collection


All objects are reference-counted. An object’s reference count is increased whenever it’s assigned to a new
name or placed in a container such as a list, tuple, or dictionary, as shown here:

In [13]:

a = 5 # Creates an object with value 37


b = a # Increases reference count on 37
c = []
c.append(b) # Increases reference count on 37

file:///Users/adityasingh/Downloads/Classes & Objects.html 4/15


6/17/2019 Classes & Objects

This example creates a single object containing the value 37. a is merely a name that refers to the newly
created object. When b is assigned a, b becomes a new name for the same object and the object’s
reference count increases. Likewise, when you place b into a list, the object’s reference count increases
again. Throughout the example, only one object contains 37. All other operations are simply creating new
references to the object. An object’s reference count is decreased by the del statement or whenever a refer-
ence goes out of scope (or is reassigned). The current reference count of an object can be obtained using
the sys.getrefcount() function.

In [15]:

import sys
print(sys.getrefcount(a))

245

In many cases, the reference count is much higher than you might guess. For immutable data such as
numbers and strings, the interpreter aggressively shares objects between dif- ferent parts of the program in
order to conserve memory. When an object’s reference count reaches zero, it is garbage-collected. However,
in some cases a circular dependency may exist among a collection of objects that are no longer in use.

In [16]:

a={}
b={}
a['b'] = b # a contains reference to b
b['a'] = a # b contains reference to a
del a
del b

In this example, the del statements decrease the reference count of a and b and destroy the names used to
refer to the underlying objects. However, because each object con- tains a reference to the other, the
reference count doesn’t drop to zero and the objects remain allocated (resulting in a memory leak). To
address this problem, the interpreter periodically executes a cycle detector that searches for cycles of
inaccessible objects and deletes them. The cycle-detection algorithm runs periodically as the interpreter
allocates more and more memory during execution. The exact behavior can be fine-tuned and controlled
using functions in the gc module.

References & Copies


When a program makes an assignment such as a = b, a new reference to b is created. For immutable
objects such as numbers and strings, this assignment effectively creates a copy of b. However, the behavior
is quite different for mutable objects such as lists and dictionaries.

file:///Users/adityasingh/Downloads/Classes & Objects.html 5/15


6/17/2019 Classes & Objects

In [18]:

a = [1,2,3,4]
b = a
print(b is a)
b[2]= -100
print(a)

True
[1, 2, -100, 4]

Because a and b refer to the same object in this example, a change made to one of the variables is reflected
in the other.To avoid this, you have to create a copy of an object rather than a new reference. Two types of
copy operations are applied to container objects such as lists and dic- tionaries: a shallow copy and a deep
copy. A shallow copy creates a new object but popu- lates it with references to the items contained in the
original object.

In [11]:

a = [1,2,[3,4]]
b = list(a)
b is a

Out[11]:

False

In [12]:

b.append(100)
print(b)
print(a)

[1, 2, [3, 4], 100]


[1, 2, [3, 4]]

In [13]:

b[2][0] = -100
print(b)
print(a)

[1, 2, [-100, 4], 100]


[1, 2, [-100, 4]]

In this case, a and b are separate list objects, but the elements they contain are shared. Therefore, a
modification to one of the elements of a also modifies an element of b, as shown. A deep copy creates a
new object and recursively copies all the objects it contains. There is no built-in operation to create deep
copies of objects. However, the copy.deepcopy() function in the standard library can be used, as shown in
the following example:

In [15]:

import copy
a = [1,2,[3,4]]
b = copy.deepcopy(a)

file:///Users/adityasingh/Downloads/Classes & Objects.html 6/15


6/17/2019 Classes & Objects

First Class Objects

All objects in Python are said to be “first class.”This means that all objects that can be named by an
identifier have equal status. It also means that all objects that can be named can be treated as data. For
example, here is a simple dictionary containing two values:

In [22]:

items = {
'number' : 42,
'text' : "Hello World"
}

The first-class nature of objects can be seen by adding some more unusual items to this dictionary.

In [24]:

items["func"] = abs
print(items["func"](-45))

45

The fact that everything in Python is first-class is often not fully appreciated by new programmers. However,
it can be used to write very compact and flexible code. For example, suppose you had a line of text such as
"GOOG,100,490.10" and you wanted to convert it into a list of fields with appropriate type-conversion.
Here’s a clever way that you might do it by creating a list of types (which are first-class objects) and execut-
ing a few simple list processing operations:

In [25]:

line = "GOOG,100,490.10"
field_types = [str, int, float]
raw_fields = line.split(',')
fields = [ty(val) for ty,val in zip(field_types,raw_fields)]
print(fields)

['GOOG', 100, 490.1]

In [26]:

print(type(None))

<class 'NoneType'>

file:///Users/adityasingh/Downloads/Classes & Objects.html 7/15


6/17/2019 Classes & Objects

Classes
(TODO : Not very clear. Requires a lot of work)
Reference : Corey Schafer

A class in Python is effectively a data type. All the data types built into Python are classes, and Python gives
you powerful tools to manipulate every aspect of a class’s behavior.

A class variable is a variable associated with a class, not an instance of a class, and is accessed by all
instances of the class, in order to keep track of some class-level information, such as how many instances
of the class have been created at any point in time. Python provides class variables, although using them
requires slightly more effort than in most other languages. Also, you need to watch out for an interaction
between class and instance variables. They can be invoked by classname.classvariable

When Python is looking up an instance variable, if it can’t find an instance variable of that name, it will then
try to find and return the value in a class variable of the same name. Only if it can’t find an appropriate class
variable will it signal an error. This does make it efficient to implement default values for instance variables;
just create a class variable with the same name and appropriate default value, and avoid the time and
memory overhead of initializing that instance variable every time a class instance is created. But this also
makes it easy to inadvertently refer to an instance variable rather than a class variable, without signaling an
error.

Just as in Java, you can invoke static methods even though no instance of that class has been created,
although you can call them using a class instance. To create a static method, use the @staticmethod
decorator,

Class methods are similar to static methods in that they can be invoked before an object of the class has
been instantiated or by using an instance of the class. But class methods are implicitly passed the class they
belong to as their first parameter, so you can code them more simply,

In [34]:

class SimpleClass:
pass

sc = SimpleClass()
sc.myattr = "hello world"

print(sc.myattr)

hello world

file:///Users/adityasingh/Downloads/Classes & Objects.html 8/15


6/17/2019 Classes & Objects

In [16]:

class Account(object):
num_accounts = 0
def __init__(self,name,balance):
self.name = name
self.balance = balance
Account.num_accounts += 1
def __del__(self):
Account.num_accounts -= 1
def deposit(self,amt):
self.balance = self.balance + amt
def withdraw(self,amt):
self.balance = self.balance - amt
def inquiry(self):
return self.balance

The values created during the execution of the class body are placed into a class object that serves as a
namespace much like a module. For example, the members of the Account class are accessed as follows:

In [17]:

Account.num_accounts
Account.__init__
Account.__del__
Account.deposit
Account.withdraw
Account.inquiry

Out[17]:

<function __main__.Account.inquiry(self)>

It’s important to note that a class statement by itself doesn’t create any instances of the class (for example,
no accounts are actually created in the preceding example). Rather, a class merely sets up the attributes that
will be common to all the instances that will be created later. In this sense, you might think of it as a
blueprint. The functions defined inside a class are known as instance methods. An instance method is a
function that operates on an instance of the class, which is passed as the first argument. By convention, this
argument is called self, although any legal identifier name can be used. In the preceding example, deposit(),
withdraw(), and inquiry() are examples of instance methods. Class variables such as num_accounts are
values that are shared among all instances of a class (that is, they’re not individually assigned to each
instance). In this case, it’s a variable that’s keeping track of how many Account instances are in existence.

Instances of a class are created by calling a class object as a function. This creates a new instance that is
then passed to the init() method of the class.The arguments to init() consist of the newly created instance
self along with the arguments supplied when calling the class object.

file:///Users/adityasingh/Downloads/Classes & Objects.html 9/15


6/17/2019 Classes & Objects

In [32]:

# Create a few accounts


a = Account("Guido", 1000.00) # Invokes Account.__init__(a,"Guido",1000.00)
b = Account("Bill", 10.00)
print(a)
print(b)

<__main__.Account object at 0x1041954a8>


<__main__.Account object at 0x104195c18>

Inside init(), attributes are saved in the instance by assigning to self. For example, self.name = name is
saving a name attribute in the instance. Once the newly created instance has been returned to the user,
these attributes as well as attrib- utes of the class are accessed using the dot (.) operator as follows:

In [22]:

a.deposit(100.00)
b.withdraw(50.00)
name = a.name

The dot (.) operator is responsible for attribute binding.When you access an attribute, the resulting value may
come from several different places. For example, a.name in the previous example returns the name attribute
of the instance a. However, a.deposit returns the deposit attribute (a method) of the Account class.When you
access an attribute, the instance is checked first and if nothing is known, the search moves to the instance’s
class instead.This is the underlying mechanism by which a class shares its attributes with all of its instances.

Although classes define a namespace, classes do not create a scope for names used inside the bodies of
methods.Therefore, when you’re implementing a class, references to attributes and methods must be fully
qualified. For example, in methods you always ref- erence attributes of the instance through self. Thus, in the
example you use self.balance, not balance. This also applies if you want to call a method from another
method, as shown in the following example:

In [25]:

class Foo(object):
def bar(self):
print("bar!")
def spam(self):
bar(self)
self.bar()
Foo.bar(self) # This also works

file:///Users/adityasingh/Downloads/Classes & Objects.html 10/15


6/17/2019 Classes & Objects

The lack of scoping in classes is one area where Python differs from C++ or Java. If you have used those
languages, the self parameter in Python is the same as the this pointer. The explicit use of self is required
because Python does not provide a means to explicitly declare variables (that is, a declaration such as int x
or float y in C). Without this, there is no way to know whether an assignment to a variable in a method is
supposed to be a local variable or if it’s supposed to be saved as an instance attribute. The explicit use of
self fixes this—all values stored on self are part of the instance and all other assignments are just local
variables.

Inheritance
Inheritance is a mechanism for creating a new class that specializes or modifies the behavior of an existing
class.The original class is called a base class or a superclass.The new class is called a derived class or a
subclass.When a class is created via inheritance, it “inherits” the attributes defined by its base classes.
However, a derived class may redefine any of these attributes and add new attributes of its own. Inheritance
is specified with a comma-separated list of base-class names in the class statement. If there is no logical
base class, a class inherits from object, as has been shown in prior examples. object is a class which is the
root of all Python objects and which provides the default implementation of some common methods such as
str(), which creates a string for use in printing.Inheritance is often used to redefine the behavior of existing
methods.As an example, here’s a specialized version of Account that redefines the inquiry() method to
periodically overstate the current balance with the hope that someone not paying close attention will
overdraw his account and incur a big penalty when making a payment on their subprime mortgage:

In [26]:

import random
class EvilAccount(Account):
def inquiry(self):
if random.randint(0,4) == 1:
return self.balance * 1.10
else:
return self.balance

# Note: Patent pending idea


c = EvilAccount("George", 1000.00)
c.deposit(10.0) # Calls Account.deposit(c,10.0) available = c.inquiry() # Calls
EvilAccount.inquiry(c)

In this example, instances of EvilAccount are identical to instances of Account except for the redefined
inquiry() method. Inheritance is implemented with only a slight enhancement of the dot (.) operator.
Specifically, if the search for an attribute doesn’t find a match in the instance or the instance’s class, the
search moves on to the base class.This process continues until there are no more base classes to search. In
the previous example, this explains why c.deposit() calls the implementation of deposit() defined in the
Account class. A subclass can add new attributes to the instances by defining its own version of init(). For
example, this version of EvilAccount adds a new attribute evilfactor:

file:///Users/adityasingh/Downloads/Classes & Objects.html 11/15


6/17/2019 Classes & Objects

In [27]:

class EvilAccount(Account):
def __init__(self,name,balance,evilfactor):
Account.__init__(self,name,balance) # Initialize Account
self.evilfactor = evilfactor
def inquiry(self):
if random.randint(0,4) == 1:
return self.balance * self.evilfactor
else:
return self.balance

When a derived class defines init(), the init() methods of base classes are not automatically
invoked.Therefore, it’s up to a derived class to perform the proper initialization of the base classes by calling
their init() methods. In the previous example, this is shown in the statement that calls Account.init(). If a base
class does not define init(), this step can be omitted. If you don’t know whether the base class defines init(),
it is always safe to call it without any arguments because there is always a default implementation that
simply does nothing.

Occasionally, a derived class will reimplement a method but also want to call the original implementation.To
do this, a method can explicitly call the original method in the base class, passing the instance self as the
first parameter as shown here:

In [28]:

class MoreEvilAccount(EvilAccount):
def deposit(self,amount):
self.withdraw(5.00) # Subtract the "convenience" fee
EvilAccount.deposit(self,amount) # Now, make deposit

A subtlety in this example is that the class EvilAccount doesn’t actually implement the deposit() method.
Instead, it is implemented in the Account class. Although this code works, it might be confusing to someone
reading the code (e.g., was EvilAccount sup- posed to implement deposit()?).Therefore, an alternative
solution is to use the super() function as follows:

In [29]:

class MoreEvilAccount(EvilAccount):
def deposit(self,amount):
self.withdraw(5.00) # Subtract convenience fee
super(MoreEvilAccount,self).deposit(amount) # Now, make deposit

super(cls, instance) returns a special object that lets you perform attribute lookups on the base classes. If
you use this, Python will search for an attribute using the normal search rules that would have been used on
the base classes.This frees you from hard-coding the exact location of a method and more clearly states
your intentions (that is, you want to call the previous implementation without regard for which base class
defines it). Unfortunately, the syntax of super() leaves much to be desired. If you are using Python 3, you can
use the simplified statement super().deposit(amount) to carry out the calculation shown in the example. In
Python 2, however, you have to use the more verbose version. Python supports multiple inheritance.This is
specified by having a class list multiple base classes. For example, here are a collection of classes:

file:///Users/adityasingh/Downloads/Classes & Objects.html 12/15


6/17/2019 Classes & Objects

In [30]:

class DepositCharge(object):
fee = 5.00
def deposit_fee(self):
self.withdraw(self.fee)

class WithdrawCharge(object):
fee = 2.50
def withdraw_fee(self):
self.withdraw(self.fee)

# Class
class MostEvilAccount(EvilAccount, DepositCharge, WithdrawCharge):
def deposit(self,amt):
self.deposit_fee()
super(MostEvilAccount,self).deposit(amt)
def withdraw(self,amt):
self.withdraw_fee()
super(MostEvilAcount,self).withdraw(amt)

When multiple inheritance is used, attribute resolution becomes considerably more complicated because
there are many possible search paths that could be used to bind attributes.To illustrate the possible
complexity, consider the following statements

In [ ]:

d = MostEvilAccount("Dave",500.00,1.10)
d.deposit_fee() # Calls DepositCharge.deposit_fee(). Fee is 5.00
d.withdraw_fee() # Calls WithdrawCharge.withdraw_fee(). Fee is 5.00 ??

In this example, methods such as deposit_fee() and withdraw_fee() are uniquely named and found in their
respective base classes. However, the withdraw_fee() function doesn’t seem to work right because it doesn’t
actually use the value of fee that was initialized in its own class. What has happened is that the attribute fee
is a class variable defined in two different base classes. One of those values is used, but which one? (Hint:
it’s DepositCharge.fee.)

Static Methods
In a class definition, all functions are assumed to operate on an instance, which is always passed as the first
parameter self. However, there are two other common kinds of methods that can be defined. A static
method is an ordinary function that just happens to live in the namespace defined by a class. It does not
operate on any kind of instance.To define a static method, use the @staticmethod decorator as shown here:

In [35]:

class Foo(object):
@staticmethod
def add(x,y):
return x + y

file:///Users/adityasingh/Downloads/Classes & Objects.html 13/15


6/17/2019 Classes & Objects

In [36]:

x = Foo.add(2,3)
x

Out[36]:

A common use of static methods is in writing classes where you might have many dif- ferent ways to create
new instances. Because there can only be one init() func- tion

Class methods are methods that operate on the class itself as an object. Defined using the @classmethod
decorator, a class method is different than an instance method in that the class is passed as the first
argument which is named cls by convention. For example:

In [42]:

#In this example, notice how the class TwoTimes is passed to mul() as an object.
class Times(object):
factor = 1
@classmethod
def mul(cls,x):
return cls.factor*x

class TwoTimes(Times):
factor = 2

x = TwoTimes.mul(4)
x

Out[42]:

Properties
Normally, when you access an attribute of an instance or a class, the associated value that is stored is
returned.A property is a special kind of attribute that computes its value when accessed.

file:///Users/adityasingh/Downloads/Classes & Objects.html 14/15


6/17/2019 Classes & Objects

In [45]:

import math
class Circle(object):
def __init__(self,radius):
self.radius = radius
# Some additional properties of Circles @property
def area(self):
return math.pi*self.radius**2
@property
def perimeter(self):
return 2*math.pi*self.radius

c = Circle(4)
c.perimeter

Out[45]:

25.132741228718345

file:///Users/adityasingh/Downloads/Classes & Objects.html 15/15