# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ## Welcome to Python
#
# Python is a programming language which can be used to make computer games, cross platform softwares, website applications and much more.
#
#
# ## Download and Installation
#
# Visit the offical website - https://www.python.org/
#
#

# ## Math Basics

# +
# Addition

3 + 4

# +
# Multiplication

5 * 20

# +
# Bodmas

8 + 2 * 10

# +
# Paranthesis

(8 + 2) * 10

# +
# Float Division
# Returns the actual division output

18 / 4

# +
# Integral Division
# Returns the integer part of the division

18 // 4

# +
# Remainder

18 % 4

# +
# Exponent

5 ** 3

# + [markdown] slideshow={"slide_type": "subslide"}
# ## Input/Output

# + slideshow={"slide_type": "fragment"}
# Takes some input from the user
x = input('Input : ')

# Prints out the same as output
print('Output : ' + x)
# -

# ## Data Types

# ### Integers

x = 5
y = 5

x + y

5 ** x

# ### Strings

'String is comprised of characters in quotes'

"It also works in double quotes"

# +
# 'I don't think if this works'

# +
# Escaping character

'I don\'t think this will create any problem.'

# +
# Use double quotes to remove this type of problem

"Just don't use single quotes!!"

# +
# Formatting Characters

# Tab - '\t'
# Newline - '\n'

print('C:\Desktop\newfolder')

# +
# Use r to consider the raw string i.e. without any formatting

print(r'C:\Desktop\newfolder')

# +
# String multiplication

x = 'String '
x * 5

# +
# String Concatenation

'Rajat ' + 'Goyal'

# +
# Integer to String Conversion

quantity = 5
denomination = " Rupees"

str(quantity) + denomination

# +
name = '<NAME>'

# Substring of a string by defining the range
name[3:8]
# -

# Substring by defining the start index
name[6:]

# Substring by defining the end index
name[:8]

# Substring without any index specified will return the original string
name[:]

# +
# Print function which outputs the value on the console screen

print("Hello World")

# +
# Length of a string - Blankspace also counts as a character

len("Hello World")
# -

# ### Characters

# +
name = "<NAME>"

# Access characters of string which is 0-indexed using square brackets
name[0]
# -

# Access characters from the last using -1 indexing
name[-1]

# ### Lists

# +
# Define a list of primitive data types

marks = [49, 53, 87, 65, 71]

# +
# Access the list which is 0-indexed i.e. (0, 1, 2, ... , n-1)

marks[0]

# +
# Change any value in the list

marks[2] = 57

marks

# +
# Add new elements to the list

updatedMarks = marks + [84, 68]
updatedMarks

# +
# Add elements one at a time

marks.append(91)
marks

# +
# Sublist of a list

marks[:2]

# +
# Change sublist to a new list

marks[:2] = [0]
marks
# -

# ### Sets
#
# Sets do not contain any element twice

subjects = {'Mathematics', 'Physics', 'Chemistry', 'English', 'Economics'}
print(subjects)

if 'Physics' in subjects:
    print("It's gonna be fun!!")
else:
    print('-_-')

# ### Dictionaries
#
# Dictionary is a set of key value pair

# +
students = {59:'Rajat', 64:'Rohan', 66:'Rohit'}

print(students)
print(students[64])

# +
# Iterate over all elements of the dictionary

for key, value in students.items():
    print(str(key) + " : " + value)
# -

# ## Loops

# ### If

# +
age = 27

if age >= 18:
    print("I can vote now!")
# -

# ### If-Else

# +
name = "Rajat"

if name is "Rajat":
    print('Hello Lord!')
else:
    print("I don't know ya")
# -

# ### If - Else If - Else

# +
num = 18

if num % 15 == 0:
    print("FooBar")
elif num % 5 == 0:
    print("Foo")
elif num % 3 == 0:
    print("Bar")
else:
    print("Nothing")
# -

# ### For

# +
foods = ['bacon', 'tuna', 'ham', 'beef']

for f in foods:
    print(f)
    print(len(f))
# -

# ### Range

# 1 argument - [0,n-1]
for x in range(5):
    print(x)

# 2 arguments - [a, b-1]
for x in range(1, 6):
    print(x)

# 3 arguments - arithmetic progression with 3rd argument as the difference
for x in range(0, 25, 5):
    print(x)

# ### While

# +
num = 5

while num < 10:
    print("Num :", num)
    num += 1
# -

# ## Flow Control

# ### Break

# +
number = 5

for n in range(11):
    if n is number:
        print("Found the number!!")
        break
    print('-')
# -

# ### Continue

# +
number = 5

for n in range(11):
    if n is number:
        print("Skip the number!!")
        continue
    print(n)
# -

# ## Comments

# ### Single Line

# +
# This is a single line comment
# -

# ### Multi Line

# +
print('Hello')

'''
Triple quotes are used for
    - multi
    - line
    - comments
'''

print('world')


# -

# ## Functions

# +
# Defining a function
def sayHello():
    print('Hello World!')

# Calling the function
sayHello()


# -

# ### Parameters

# +
# Single Parameter

def feet_to_inches(feet):
    inches = 12 * feet
    print(str(feet) + " feet = " + str(inches) + " inches")

feet_to_inches(5)
feet_to_inches(6.2)


# +
# Multiple Parameters

def calculateSimpleInterest(amount, rate, time):
    interest = (amount * rate * time) / 100
    print(interest)
    
calculateSimpleInterest(1250, 5, 3)


# -

# ### Return Values

# +
# Return statement

def calculatePercentage(obtainedMarks, totalMarks):
    percentage = (obtainedMarks / totalMarks) * 100
    return percentage

print('I scored ' + str(calculatePercentage(323, 400)) + "%")
# -

# ### Variable Scope

# +
a = 25 # Global variable

def funcA():
    b = 30 # Local variable
    print(a) # Prints out the global variable
    print(b) # Prints out the local variable
    
def funcB():
    print(a) # Prints out the global variable
    # print(b) # Variable b is not accessible here
    
funcA()
funcB()


# -

# ### Default Arguments

# +
# Default value for the parameter 'sex' is 'Unknown'
# This means that if no value is passed for the parameter 'sex', default value will be taken

def get_gender(sex='Unknown'):
    if sex is 'm':
        sex = 'Male'
    elif sex is 'f':
        sex = 'Female'
    print(sex)

get_gender('m')
get_gender('f')
get_gender()


# -

# ### Keyword Arguments

# +
# Default value of 'time' is '1 year'
# With the help of keyword arguments, we can change specific arguments also

def calculateSimpleInterest(amount=1000, rate=2, time=1):
    interest = (amount * rate * time) / 100
    print(interest)
    
calculateSimpleInterest() # Default arguments
calculateSimpleInterest(1200, 5, 2)
calculateSimpleInterest(time=2) # Specific value for parameter 'time' only
calculateSimpleInterest(time=2, rate=5) # No need to maintain the correct order


# -

# ### Flexible Number of Arguments

# +
# Use asterisk(*) to specify unknown number of arguments

def add_numbers(*args):
    total = 0
    for a in args:
        total += a
    print(total)
    
add_numbers()
add_numbers(3)
add_numbers(1, 2, 3, 4, 5)


# -

# ### Unpacking Arguments

# +
# Asterisk(*) does the unpacking of list into arguments

def calculateSimpleInterest(amount=1000, rate=2, time=1):
    interest = (amount * rate * time) / 100
    print(interest)

data = [1200, 5, 2]

calculateSimpleInterest(data[0], data[1], data[2])
calculateSimpleInterest(*data)
# -

# ## Modules
#
# With the help of modules, there is no need to rewrite functions over and over again.

# +
# Create a file test.py which acts as a module

# Import the module(thus importing all functions in it)
import test

# Call the function using the module name
test.hello()

# +
import random

x = random.randrange(1, 1000)
print(x)

# +
# From 'test' module, import specific function 'hello'
from test import hello

hello()
# -

# ### Download an image from the web

# +
import urllib.request

def download_web_image(url):
    urllib.request.urlretrieve(url, 'images/image.png')
    
download_web_image("https://www.python.org/static/opengraph-icon-200x200.png")
# -

# ### Read and write files

# +
fw = open('sample.txt', 'w')

for i in range(5):
    fw.write(str(i) + '\n')

fw.close()

# +
fr = open('sample.txt', 'r')

data = fr.read()
print(data)

fr.close()
# -

# ## Exception

while True:
    try:
        x = int(input('\nEnter a number \n'))
        print(50/x)
        break
    except ValueError:
        # If input contains anything other than digits
        print('Oops! Please enter a number only.')
    except ZeroDivisionError:
        # If input is equal to zero
        print("Don't pick zero")
    except:
        # All other errors will be caught by this method
        break
    finally:
        # This is called in every case
        print('Loop complete')


# ## Classes and Objects

class Class:
    
    variable = 10
    
    def incrementVariable(self):
        self.variable += 1
        
    def decrementVariable(self):
        self.variable -= 1
        
    def printVariable(self):
        print(self.variable)


# +
# Creating an object
obj = Class()

# Calling the member functions of the class using the object
obj.printVariable()
obj.incrementVariable()
obj.printVariable()
obj.decrementVariable()
obj.printVariable()

# +
# Different objects have different memory blocks associated for class member variables
obj1 = Class()
obj2 = Class()

obj1.incrementVariable()
obj2.decrementVariable()

obj1.printVariable()
obj2.printVariable()


# -

# ### init function

class Class:
    
    # Constructor helps in constructing objects
    def __init__(self, x=10):
        self.variable = x
        
    def printVariable(self):
        print(self.variable)


# +
# Initiating an object will first call the constructor i.e init function
obj = Class()
obj1 = Class(32)

obj.printVariable()
obj1.printVariable()


# -

# ### Class Variables vs Instance Variables

# +
class Girl:
    
    # Class variables are shared by all instances of the class
    gender = 'female'
    
    def __init__(self, name):
        # For each object of the class, instance variables are different
        self.name = name
        
r = Girl('name1')
s = Girl('name2')

print(r.gender)
print(s.gender)
print(r.name)
print(s.name)


# -

# ## Inheritance

# +
class Parent():
    
    def print_last_name(self):
        print('Last Name')


class Child(Parent):
    
    def print_first_name(self):
        print('First Name')


child = Child()
child.print_first_name()

# We can call the parent class functions also on any object of child class
child.print_last_name()


# -

# ### Overriding

# +
class Parent():
    
    def print_last_name(self):
        print('Last Name')
        

class Child(Parent):
    
    def print_first_name(self):
        print('First Name')
    
    # Overriding a function already present in the parent class
    def print_last_name(self):
        print('Another Last Name')
        
        
child = Child()
child.print_first_name()

# New function defined in child class overrides the parent function
child.print_last_name()


# -

# ## Multiple Inheritance
#
# Inherting the functions from two or more classes

# +
class A():
    
    def funcA(self):
        print('Function of class A')
    
class B():

    def funcB(self):
        print('Function of class B')

# Multiple inheritance
class C(A, B):
    
    # If no function or class variable in present in class, we have to write the keyword 'pass'
    pass

c = C()
c.funcA()
c.funcB()
# -

# ## Threading

# +
import threading

class Messenger(threading.Thread):
    
    def run(self):
        for _ in range(10):
            print(threading.currentThread().getName())
            
x = Messenger(name = 'Send out messages')
y = Messenger(name = 'Receive messages')

x.start()
y.start()
# -

# ### Unpacking Lists

# +
details = ['Rajat', 'Goyal', 20]

# Unpacking a list into different variables
first_name, last_name, age = details

print(first_name)
print(last_name)
print(age)

# +
# In the above example, we knew the number of elements(attributes) present in the list
# We can use asterisk(*) to store the remaining elements of the list

marks = [23, 26, 76, 45, 59, 38, 94, 43]

first, *remaining, last = marks

print(first)
print(remaining)
print(last)
# -

# ### Zip function
#
# Attach two lists together

# +
first = ['Bruce', 'Tom', 'Taylor']
last = ['Wayne', 'Hanks', 'Swift']

names = zip(first, last)

for a, b in names:
    print(a, b)
# -

# ### Lambda function
#
# function_name = lambda parameter: computation

answer = lambda x: x*5
print(answer(5))

# ### Min, Max and Sorting Dictionaries

# +
marks = {
    'physics' : 93,
    'mathematics' : 95,
    'chemistry' : 93,
    'english' : 90,
    'physical education' : 98
}

# Minimum according to the alphabetical order of keys
print(min(zip(marks.keys(), marks.values())))

# Minimum according to the numerical value
print(min(zip(marks.values(), marks.keys())))

# Maximum of all the values
print(max(zip(marks.values(), marks.keys())))

# Sorted list of tuples
print(sorted(zip(marks.values(), marks.keys())))
# -

# ### Struct

# +
from struct import *

# Store as bytes data
packed_data = pack('iif', 6, 19, 4.73)
print(packed_data)
# -

print(unpack('iif', packed_data))

# ### Map function

# +
income = [10, 30, 75]

def double_money(money):
    return money * 2

new_income = list(map(double_money, income))
print(new_income)
# -

# ## Bitwise Operators

# ### AND

# +
a = 50     # 110010
b = 25     # 011001

c = a & b  # 010000
print(c)
# -

# ### OR

# +
a = 50     # 110010
b = 25     # 011001

c = a | b  # 111011
print(c)
# -

# ### Left and Right Shift

# +
a = 240     # 11110000

# Left shift
b = a << 2  # 1111000000
print(b)

# Right shift
b = a >> 2  # 00111100
print(b)
# -

# ### Finding Largest or Smallest Items

# +
import heapq

grades = [32, 43, 654, 34, 132, 66, 99, 532]

print(heapq.nlargest(3, grades))

# +
stocks = [
    {'ticker': 'AAPL', 'price': 201},
    {'ticker': 'GOOG', 'price': 800},
    {'ticker': 'F', 'price': 54},
    {'ticker': 'MSFT', 'price': 313},
    {'ticker': 'YHOO', 'price': 68},
]

print(heapq.nsmallest(2, stocks, key=lambda stock: stock['price']))
# -

# ### Finding most frequent items

# +
from collections import Counter

text = "Python can be easy to pick up whether you're a first time programmer or you're experienced with other languages. The following pages are a useful first step to get on your way writing programs with Python!"

words = text.split()

counter = Counter(words)
top_three = counter.most_common(3)
print(top_three)

StarcoderdataJupyterScriptsDedupFiltered