Python: Basics

Why Python?

  • Easy to learn
  • Easier to read
  • Easiest to write
  • `import`

Installation

  • Python is preinstalled in most GNU/Linux systems
  • Python2 available as `python` and Python3 as `python3` on Ubuntu
  • Python uses `pip` package manager to install new modules
  • Python2: `apt-get install python-pip`
  • Python3: `apt-get install python3-pip`

For this tutorial, we will use python3

python2 vs python3: https://r93.in/cu

Python CLI

  • Read
  • Evaluate
  • Print
  • Loop

First steps

Open the python3 cli by `python3`

and try these commands

  1. 2+2
  2. x = 5
  3. y = 6
  4. x*y
  5. print x*y
  6. print (x*y)
  7. _
  8. _*2

9. Ctrl + z

10. `fg` then <enter>

11. Ctrl + d

12. `python3`

13. 3/2

14. 3//2

15. 2**31

Control Flow Statements - for, while, if

All control flow statements end with a colon ':'

Tells the interpreter to expect the body thereafter

Whitespace

  • Python uses indentation levels to demarcate code instead of braces in many languages like C++
  • The leading 'whitespace' is of importance
  • You can use tabs or spaces to indent the code
  • 4 spaces is the convention, so stick to it
  • Never mix tabs and spaces in the same or consecutive lines in a level - Python interpreter will complain
  • It is possible to use different types and amounts of whitespaces in different levels but strictly avoid it - makes the code horrible
  • Each indentation level build upon the previous ones

Indentation levels

Indentation example

Python Standard Library

  • Standard modules can be imported by:                              `import <module_name>` -> `import math`

 

 

  • run `help (math)` | scroll by pressing <enter>, exit by <q>
  • run `help (math.<func_name>)` to access func's help string

Everything is an object

In python, everything is an object.

An object can have various properties like variables, functions.

Like many languages, object properties in python are accessed by the '.' (dot) operator.

 

Try playing with the 'math' object

Various types of imports

  • `import math`
  • `from math import factorial`
  • `from math import factorial as fac`

Other standard libraries

  • OS: `import os`
  • SYS: `import sys`
  • TIME: `import time`

Very Large Integers

  • Most languages have a limit on how big an integer you can use.
  • For very large integers you have to use specialised classes like 'BigInteger' in java
  • Python has no such problem
  • The size of the integer is only limited by the amount of RAM your system has
  • try: `fac(100)`
  • try: `fac(1000)`
  • try: `fac(10000)`

clear your screen:`CTRL + L`

Scalar types: int

We have already seen that integers in python can have infinite precision

 

         Integers can be specified as:

  • Decimal: `10`
  • Binary: `0b10`
  • Octal: `0o10`
  • Hexadecimal: `0x10`

Converting to integers

  • from float:`int(3.5)`
  • from strings: `int('3')`
  • from one base to base 10: `int('<num>', <base>)` -> `int('100', 2)`

Scalar types: float

If the number has a '.' or a 'e', it is interpreted as float by python.

 

Try:

  • `3.5`
  • `1e8`
  • `1e-15`

Converting to float

  • `float(3)`
  • `float('3.5')`
  • `float('nan')`
  • `float('inf')`
  • `float('-inf')`
  • `3.0 + 1`

Scalar types: None

None is literally none.

None means it is not there (different from not defined)

 

  • `print (x)`

This will give error:

This will not give error:

  • `x = None`
  • `print (x)`

Can be checked by:

  • `a = None`
  • `a is None` (will return True)

Scalar types: Bool

  • True and False (inital capitals)
  • bool constructor
  • 0 is considered 'falsy' and all other values (+ve/-ve) are considered 'true'
  • empty collections (like strings, lists) are falsy

Conditional Statements

  • ==
  • >=
  • <=
  • >
  • <
  • !=

Return True or False based on the validity of the statement

Like most other languages, '=' is for assignment and not for comparison

Example: `3==2` gives False

Conditional statements: if

if expr:
    print('expr is True')

`if` statement converts the expr to bool as if the bool constructor was doing so and checks whether it is True, if yes, then it executes the relevant code defined by the next indentation level in the consecutive lines

if -elif-else

if True:
    print('#yolo')
else:
    print('#swag')
a = 20
if a > 20:
    print('above 20')
elif a < 20:
    print('less than 20')
else:
    print('it is twunty')

If the code to be executed is small enough, we can write it in the same line as if statement

>>> if True: print('bwahaha')

Conditional Statements: while

a  = 5
while a != 0:
    print(a)
    a -= 1

while loop runs while the expr is True

but it can break out of the loop if we explicitly issue a break statement

while True:
    num = int(input('Enter da numba: '))
    if num % 7 == 0:
        break
    else:
        print('wrong numba')

Collections: str (string)

immutable sequences of Unicode code points

  • immutable: once created, cannot be modified
  • Unicode code points (code positions): any of the numerical values that make up the code space - like 128 chars (aA-zZ-0-9) in ascii.

example: "This is a string", 'This is also a string'

"But this gives an error because inconsistent use of quotes'

Strings with newline characters

Multiline strings (delimited by 3 quote chars rather than 1):

>>> a = """This is an awesome
    new multiline
    string"""

>>> b = '''Another awesome
    new multiline
    string'''

>>> a
>>> b

Escape sequences:

>>> a = 'This is an awesome\nnew multiline\nstring'
>>> a

newlines are messy

But don't worry, Python3 has 'Universal newline import' that does the translation based on platform for you (PEP 278). So simply use '\n'.

More escape sequences

All the escape sequences start with a '\'

a = 'Is this an escape sequence: \\'
print(a)

More about escape sequences:

http://bit.ly/1LgfFki

These escape sequences are used to insert special characters in the string (like newline).

Raw strings

What if you have lots of '\' in your string and don't want to deal with escape sequences?

Raw strings to help (prefix the opening quote with 'r')

--- Interpreted as is---

a = r'This is mah osum \ backslash. Another osum backslash: \something\n'
print(a)

notice that newline character has no effect on printing

Conversion to strings

  • `str(1)`
  • `str(1.1)`
  • `str(1e11)`

Querying the strings

Unlike many other languages, there is no separate character type in python. Chars are simply strings with width 1.

Since string is a sequence, we can query the individual characters like this for string (s):

  • first char: `s[0]`
  • last char: `s[-1]`
  • second-last char: `s[-2]`

strings in python are not terminated by '\0' like in C++, so if `s = 'hello'`, s[-1] will be 'o'

String methods

Try: `help(str)`

This lists all the methods supported by str.

>>> s = '  hello'
>>> r = 'world!'
>>> r.capitalize()
>>> s + r
>>> l = s + r
>>> l
>>> l.split()
>>> l.split('w')
>>> l.lstrip()
>>> l.rstrip()
>>> l.strip()
>>> l.strip('!')

          Let's try some:

Chaining the methods

Methods can be chanined together

>>> a = 'hello world!     '
>>> a.capitalize().strip().strip('!')

Using international characters

Python3 strings are fully Unicode capable, therefore international characters can be used easily.

Default encoding is UTF-8.

         For example:

>>> p = 'देव सर स्वत चैव ततजयम उदरयेत'
>>> p

Alternatively you can use hexadecimal representation of unicode code points with escape sequences (just google for the hex codes):

>>> p = '\u20B9'
>>> p

Substituting values in strings

To substitute some value in a string, use the format method

>>> a = 10
>>> 'The number of people in this room is {}'.format(a)
>>> b = 'yes'
>>> c = 'no'
>>> string = 'I want to say {}, but I will say {}'
>>> string.format(b, c)
>>> string.format(c, b)
>>> 'I want to say {0}, but I will say {1} and I said {0}'.format(b, c)

Collections: bytes

Bytes are sequences of... bytes (and not unicode code points)

Used for raw binary data

         Example:

  • b'data'
  • b"data"

Bytes support most of the common string methods like splitting.

To convert between bytes and strings, you must know the enoding of the bytes.

Converting to and from bytes

Lets take a look at our previous example:

>>> p = 'देव सर स्वत चैव ततजयम उदरयेत'

We have created a new string with encoding 'utf-8' (python default). To convert this to bytes, we need to specify the encoding (using the encode method of strings):

>>> r = p.encode('utf-9')
>>> r

To decode it, we again specify the encoding (which tells us how to interpret the bytes):

>>> s = r.decode('utf-8')
>>> s
>>> s = r.decode('latin-1')
>>> s

Why is understanding bytes important?

Because files, network resources are transmitted as byte strings whereas we prefer to work with the convenient unicode strings.

MUST READ: http://bit.ly/19aB0xB

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Collections: Lists (and Tuples)

Lists and Tuples are collections that can contain other objects of any type (unlike string which can only contain sequence of chars)

Tuples are immutable, enclosed in parenthesis

>>> mahtuple = ('hey', 'yo' ,7)
>>> mahtuple
>>> print(mahtuple)
>>> print(mahtuple(1))
>>> #This will give error
>>> mahtuple.append('newthing')

Lists are mutable, enclosed in brackets

>>> mahlist = ['hey', 'yo', 7]
>>> mahlist
>>> print(mahlist)
>>> print(mahlist[1])
>>> #this will not give error
>>> mahlist.append('newthing')
>>> mahlist
>>> #this will give error
>>> mahlist[5] = 'lol'

Creating lists

>>> a = list('characters')
>>> a
>>> b = ['this',
         'is',
         'mah',
         'osum',
         'list'
        ]
>>> b

Deleting items

>>> b
>>> b.pop(0) # deletes item at index 0
>>> b
>>> b.remove('is') # finds and deletes first occurence of 'is' from left
>>> b

Collections: dict (Dictionary)

Dictionaries are key-value pairs separated by a ':'

>>> a = {
  'name': 'Ashish',
  'addr': 'G-88'
}

>>> a

Notice how the order of keys is not preserved.

New key assignment:

>>> a['roll'] = '14116020'
>>> a

Getting keys, values

>>> a['name']
>>> a['addr']
>>> a
>>> a.keys()
>>> a.values()

Deleting entries

>>> a.pop('roll')
>>> a

The for loop

'for' loop runs the code specified by the next indentation level multiple times

>>> cities = ['Delhi', 'Roorkee', 'Lahore']
>>> for city in cities:
        print(city)

        On lists:

On strings:

>>> s = 'Roorkee'
>>> for chr in s:
        print(chr)

On dicts:

>>> mahdict = {'mahlife': 'mahrulez', 'hello': 'world'}
>>> for thing in mahdict:
        print(thing, mahdict[thing])

more for loop examples:

On ranges:

>>> for i in range(3):
        print(i)
>>> for i in range(1, 4):
        print(i)
>>> for i in range(1, 8, 2):
        print(i)

Creating python modules

A python module is a small code snippet that can may work alone or work by importing in another module.

Create a file 'test.py' and open it in a text editor

from math import factorial as fac

n = 5
r = 2
output = int(fac(n)/(fac(r)*fac(n-r)))

print('There are {} ways to select {} from {}'.format(output, r, n))

Run the file with `python3 test.py`

Importing the module

import the created module with `import <module_name>`    omit the '.py' in module_name

>>> import test

You will notice that the module gets executed when imported

But what if you don't want to execute the code when imported and use it whenever you want later on??

Python Methods

>>> def mahfunc(x):
        print(x*5)
>>> mahfunc('lol')
>>> mahfunc(10)

Returning value from method:

>>> def mahfunc(x):
        return(x*5)
>>> mahfunc(10)
>>> print(mahfunc(10))

Setting default args value:

>>> def mahfunc(x = 5):
        return(x*5)
>>> print(mahfunc())
>>> print(mahfunc(10))
>>> print(mahfunc('lol'))

*args and **kwargs

You can send an arbitrary number of arguments to the method

>>> def mahfunc(*args):
        for arg in args:
            print('this is our arg: {}'.format(arg))
>>> mahfunc(10)
>>> mahfunc(10, 'lol', 'yolo')

To send named args, use **kwargs (gets passed as a dict)

>>> def mahfunc(**kwargs):
        print(kwargs)
>>> mahfunc(name = 'Ashish', addr = 'G-88)

Using *args and **kwargs together (kwargs cannot be passed before args)

>>> def mahfunc(*args, **kwargs):
        print('The args are: {}'.format(args))
        print('The kwargs are: {}'.format(kwargs))
>>> mahfunc('abc', 123, name = 'Ashish')
>>> mahfunc(name = 'Ashish')

Revisiting our test module

from math import factorial as fac

def mahfunc():
    n = 5
    r = 2
    output = int(fac(n)/(fac(r)*fac(n-r)))
    return('There are {} ways to select {} from {}'.format(output, r, n))

Importing the module again and running `mahfunc` (restart the REPL first)

>>> import test
>>> test.mahfunc()

It works! now try running `python3 test.py`

Making the module executable

Nothing happens because executing module now does nothing but declare a function (and not actually run it)

Python runtime defines some special variables. One such variable is '__name__'

When the module is imported, __name__ evaluates to the module name. When it is executed directly, it evaluates to '__main__'

>>> import test
>>> print(test.__name__)

We can use this distinction to execute our code directly!

Making the module executable

from math import factorial as fac

def mahfunc():
    n = 5
    r = 2
    output = int(fac(n)/(fac(r)*fac(n-r)))
    return('There are {} ways to select {} from {}'.format(output, r, n))

print(__name__)

This shows us that __name__ is __main__ now. Let's use this property with an if statement

from math import factorial as fac

def mahfunc():
    n = 5
    r = 2
    output = int(fac(n)/(fac(r)*fac(n-r)))
    return('There are {} ways to select {} from {}'.format(output, r, n))

def main():
    print(mahfunc())

if __name__ == "__main__": main()

Python Classes

A class is in python is the same as classes in other languages.

It encapsulates the data and the functions associated with it and allows us to make multiple instances of the object and use them as we wish.

By convention, class names in python are in written in CamelCase

A simple class

"""This is our sample class"""

class MahClass:
    def test(self):
        return('this is only a test')

    def test2(self):
        print(self.test)

Each method that is to be called on a class object or has to be called from a class instance has to accept 'self' as an argument.

'self' is similar to 'this' in java

Creating the initialisation method

The __init__ method is called by the python runtime when an instance of the class is created. It should not return any value. This is a constructor so can be used to initialise variables to some values.

"""This is our sample class"""

class MahClass:
    def __init__(self):
        self.__mahname = 'Ashish'

    def test(self):
        print('lol')
        return(self.__mahname)
mhnm = MahClass()
print(mhnm.test())

Sending args to __init__

"""This is our sample class"""

class MahClass:
    def __init__(self, name = 'Ashish'):
        self.__mahname = name

    def test(self):
        print('lol')
        return(self.__mahname)
mhnm = MahClass(name = 'Testname')
print(mhnm.test())

or

mhnm = MahClass()
print(mhnm.test())

OOP: Getters and Setters

"""This is our sample class"""

class MahClass:
    def __init__(self, name = 'Ashish'):
        self.__mahname = name

    def getName(self):
        return(self.__mahname)
    
    def setName(self, newname):
        self.__mahname = newname
mhnm = MahClass(name = 'Anothername')
print(mhnm.getName())
mhnm.setName('SuperPro')
mhnm.getName()

Getters and Setters can also be used by declaring variables as properties (out of scope for now) but do read about it.

Documenting the code

Recall how we use help(module_name) to get help about it.

But how do we get provide usage help about the modules we create?

We create docstrings

"""This is a module docstring"""

from math import factorial as fac

def mahfunc():

    """This is the help we want to give.
       Even for single line docstrings, use triple quotes (must)

    Args:
         None
    Returns:
         The number of ways to select 2 things out of 5 things.
    """

    n = 5
    r = 2
    output = int(fac(n)/(fac(r)*fac(n-r)))
    return('There are {} ways to select {} from {}'.format(output, r, n))

def main():
    print(mahfunc())

if __name__ == "__main__": main()

Testing docstrings

>>> import test
>>> help(test)
>>> help(test.mahfunc)

Code comments in python

Explains the code implementation

Comments in python are written by pre-pending them with a '#'

>>> # this is mah comment

Adding Shebang

Shebang is a common string added to the top of a Unix program that tells the system what interpreter to use with the file

#! /usr/bin/python3

First we need to know the absolute path of the python interpreter

Run `which python3`

Then we add the shebang as shown:

We make the file executable by running `chmod +x test.py`

Then run the file simply as `./test.py` (without specifying python3)

Further Reading

  • Read more on how modules are imported
  • Read on inheritance
  • Read on property, getters, setters
  • Read on try/except
Made with Slides.com