Friday, December 6, 2019

Python Zero to Hero

Python zero to hero:

Python 2 vs python 3:
Many company still in python 2.
not receiving security update for python 2
More external package in python 3, it is less in python2 for support.

Environment:
 Text Editor
 IDE
 Notebook Environment
print('hello world')
python myexample.py
python
quit()
Gitub link: Pierian/Complete-python-3-Bootcamp

Numbers and more in Python!

In this lecture, we will learn about numbers in Python and how to use them.
We'll learn about the following topics:
1.) Types of Numbers in Python
2.) Basic Arithmetic
3.) Differences between classic division and floor division
4.) Object Assignment in Python

Types of numbers

Python has various "types" of numbers (numeric literals). We'll mainly focus on integers and floating point numbers.
Integers are just whole numbers, positive or negative. For example: 2 and -2 are examples of integers.
Floating point numbers in Python are notable because they have a decimal point in them, or use an exponential (e) to define the number. For example 2.0 and -2.1 are examples of floating point numbers. 4E2 (4 times 10 to the power of 2) is also an example of a floating point number in Python.
Throughout this course we will be mainly working with integers or simple float number types.
Here is a table of the two main types we will spend most of our time working with some examples:
ExamplesNumber "Type"
1,2,-5,1000Integers
1.2,-0.5,2e2,3E2Floating-point numbers
Now let's start with some basic arithmetic.

Basic Arithmetic

In [1]:
# Addition
2+1
Out[1]:
3
In [2]:
# Subtraction
2-1
Out[2]:
1
In [3]:
# Multiplication
2*2
Out[3]:
4
In [4]:
# Division
3/2
Out[4]:
1.5
In [5]:
# Floor Division
7//4
Out[5]:
1
Whoa! What just happened? Last time I checked, 7 divided by 4 equals 1.75 not 1!
The reason we get this result is because we are using "floor" division. The // operator (two forward slashes) truncates the decimal without rounding, and returns an integer result.
So what if we just want the remainder after division?
In [6]:
# Modulo
7%4
Out[6]:
3
4 goes into 7 once, with a remainder of 3. The % operator returns the remainder after division.

Arithmetic continued

In [7]:
# Powers
2**3
Out[7]:
8
In [8]:
# Can also do roots this way
4**0.5
Out[8]:
2.0
In [9]:
# Order of Operations followed in Python
2 + 10 * 10 + 3
Out[9]:
105
In [10]:
# Can use parentheses to specify orders
(2+10) * (10+3)
Out[10]:
156

Variable Assignments

Now that we've seen how to use numbers in Python as a calculator let's see how we can assign names and create variables.
We use a single equals sign to assign labels to variables. Let's see a few examples of how we can do this.
In [11]:
# Let's create an object called "a" and assign it the number 5
a = 5
Now if I call a in my Python script, Python will treat it as the number 5.
In [12]:
# Adding the objects
a+a
Out[12]:
10
What happens on reassignment? Will Python let us write it over?
In [13]:
# Reassignment
a = 10
In [14]:
# Check
a
Out[14]:
10
Yes! Python allows you to write over assigned variable names. We can also use the variables themselves when doing the reassignment. Here is an example of what I mean:
In [15]:
# Check
a
Out[15]:
10
In [16]:
# Use A to redefine A
a = a + a
In [17]:
# Check 
a
Out[17]:
20
The names you use when creating these labels need to follow a few rules:
1. Names can not start with a number.
2. There can be no spaces in the name, use _ instead.
3. Can't use any of these symbols :'",<>/?|\()!@#$%^&*~-+
4. It's considered best practice (PEP8) that names are lowercase.
5. Avoid using the characters 'l' (lowercase letter el), 'O' (uppercase letter oh), 
   or 'I' (uppercase letter eye) as single character variable names.
6. Avoid using words that have special meaning in Python like "list" and "str"


Using variable names can be a very useful way to keep track of different variables in Python. For example:
In [18]:
# Use object names to keep better track of what's going on in your code!
my_income = 100

tax_rate = 0.1

my_taxes = my_income*tax_rate
In [19]:
# Show my taxes!
my_taxes
Out[19]:
10.0
So what have we learned? We learned some of the basics of numbers in Python. We also learned how to do arithmetic and use Python as a basic calculator. We then wrapped it up with learning about Variable Assignment in Python.
Up next we'll learn about Strings!


Variable Assignment

Rules for variable names

  • names can not start with a number
  • names can not contain spaces, use _ intead
  • names can not contain any of these symbols:
    :'",<>/?|\!@#%^&*~-+
  • it's considered best practice (PEP8) that names are lowercase with underscores
  • avoid using Python built-in keywords like list and str
  • avoid using the single characters l (lowercase letter el), O (uppercase letter oh) and I (uppercase letter eye) as they can be confused with 1 and 0

Dynamic Typing

Python uses dynamic typing, meaning you can reassign variables to different data types. This makes Python very flexible in assigning data types; it differs from other languages that are statically typed.
In [1]:
my_dogs = 2
In [2]:
my_dogs
Out[2]:
2
In [3]:
my_dogs = ['Sammy', 'Frankie']
In [4]:
my_dogs
Out[4]:
['Sammy', 'Frankie']

Pros and Cons of Dynamic Typing

Pros of Dynamic Typing

  • very easy to work with
  • faster development time

Cons of Dynamic Typing

  • may result in unexpected bugs!
  • you need to be aware of type()

Assigning Variables

Variable assignment follows name = object, where a single equals sign = is an assignment operator
In [5]:
a = 5
In [6]:
a
Out[6]:
5
Here we assigned the integer object 5 to the variable name a.
Let's assign a to something else:
In [7]:
a = 10
In [8]:
a
Out[8]:
10
You can now use a in place of the number 10:
In [9]:
a + a
Out[9]:
20

Reassigning Variables

Python lets you reassign variables with a reference to the same object.
In [10]:
a = a + 10
In [11]:
a
Out[11]:
20
There's actually a shortcut for this. Python lets you add, subtract, multiply and divide numbers with reassignment using +=, -=, *=, and /=.
In [12]:
a += 10
In [13]:
a
Out[13]:
30
In [14]:
a *= 2
In [15]:
a
Out[15]:
60

Determining variable type with type()

You can check what type of object is assigned to a variable using Python's built-in type() function. Common data types include:
  • int (for integer)
  • float
  • str (for string)
  • list
  • tuple
  • dict (for dictionary)
  • set
  • bool (for Boolean True/False)
In [16]:
type(a)
Out[16]:
int
In [17]:
a = (1,2)
In [18]:
type(a)
Out[18]:
tuple

Simple Exercise

This shows how variables make calculations more readable and easier to follow.
In [19]:
my_income = 100
tax_rate = 0.1
my_taxes = my_income * tax_rate
In [20]:
my_taxes
Out[20]:
10.0
Great! You should now understand the basics of variable assignment and reassignment in Python.
Up next, we'll learn about strings!


Strings

Strings are used in Python to record text information, such as names. Strings in Python are actually a sequence, which basically means Python keeps track of every element in the string as a sequence. For example, Python understands the string "hello' to be a sequence of letters in a specific order. This means we will be able to use indexing to grab particular letters (like the first letter, or the last letter).
This idea of a sequence is an important one in Python and we will touch upon it later on in the future.
In this lecture we'll learn about the following:
1.) Creating Strings
2.) Printing Strings
3.) String Indexing and Slicing
4.) String Properties
5.) String Methods
6.) Print Formatting

Creating a String

To create a string in Python you need to use either single quotes or double quotes. For example:
In [1]:
# Single word
'hello'
Out[1]:
'hello'
In [2]:
# Entire phrase 
'This is also a string'
Out[2]:
'This is also a string'
In [3]:
# We can also use double quote
"String built with double quotes"
Out[3]:
'String built with double quotes'
In [4]:
# Be careful with quotes!
' I'm using single quotes, but this will create an error'
  File "", line 2
    ' I'm using single quotes, but this will create an error'
        ^
SyntaxError: invalid syntax
The reason for the error above is because the single quote in I'm stopped the string. You can use combinations of double and single quotes to get the complete statement.
In [5]:
"Now I'm ready to use the single quotes inside a string!"
Out[5]:
"Now I'm ready to use the single quotes inside a string!"
Now let's learn about printing strings!

Printing a String

Using Jupyter notebook with just a string in a cell will automatically output strings, but the correct way to display strings in your output is by using a print function.
In [6]:
# We can simply declare a string
'Hello World'
Out[6]:
'Hello World'
In [7]:
# Note that we can't output multiple strings this way
'Hello World 1'
'Hello World 2'
Out[7]:
'Hello World 2'
We can use a print statement to print a string.
In [8]:
print('Hello World 1')
print('Hello World 2')
print('Use \n to print a new line')
print('\n')
print('See what I mean?')
Hello World 1
Hello World 2
Use 
 to print a new line


See what I mean?

String Basics

We can also use a function called len() to check the length of a string!
In [9]:
len('Hello World')
Out[9]:
11
Python's built-in len() function counts all of the characters in the string, including spaces and punctuation.

String Indexing

We know strings are a sequence, which means Python can use indexes to call parts of the sequence. Let's learn how this works.
In Python, we use brackets [] after an object to call its index. We should also note that indexing starts at 0 for Python. Let's create a new object called s and then walk through a few examples of indexing.
In [10]:
# Assign s as a string
s = 'Hello World'
In [11]:
#Check
s
Out[11]:
'Hello World'
In [12]:
# Print the object
print(s)
Hello World
Let's start indexing!
In [13]:
# Show first element (in this case a letter)
s[0]
Out[13]:
'H'
In [14]:
s[1]
Out[14]:
'e'
In [15]:
s[2]
Out[15]:
'l'
We can use a : to perform slicing which grabs everything up to a designated point. For example:
In [16]:
# Grab everything past the first term all the way to the length of s which is len(s)
s[1:]
Out[16]:
'ello World'
In [17]:
# Note that there is no change to the original s
s
Out[17]:
'Hello World'
In [18]:
# Grab everything UP TO the 3rd index
s[:3]
Out[18]:
'Hel'
Note the above slicing. Here we're telling Python to grab everything from 0 up to 3. It doesn't include the 3rd index. You'll notice this a lot in Python, where statements and are usually in the context of "up to, but not including".
In [19]:
#Everything
s[:]
Out[19]:
'Hello World'
We can also use negative indexing to go backwards.
In [20]:
# Last letter (one index behind 0 so it loops back around)
s[-1]
Out[20]:
'd'
In [21]:
# Grab everything but the last letter
s[:-1]
Out[21]:
'Hello Worl'
We can also use index and slice notation to grab elements of a sequence by a specified step size (the default is 1). For instance we can use two colons in a row and then a number specifying the frequency to grab elements. For example:
In [22]:
# Grab everything, but go in steps size of 1
s[::1]
Out[22]:
'Hello World'
In [23]:
# Grab everything, but go in step sizes of 2
s[::2]
Out[23]:
'HloWrd'
In [24]:
# We can use this to print a string backwards
s[::-1]
Out[24]:
'dlroW olleH'

String Properties

It's important to note that strings have an important property known as immutability. This means that once a string is created, the elements within it can not be changed or replaced. For example:
In [25]:
s
Out[25]:
'Hello World'
In [26]:
# Let's try to change the first letter to 'x'
s[0] = 'x'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in ()
      1 # Let's try to change the first letter to 'x'
----> 2 s[0] = 'x'

TypeError: 'str' object does not support item assignment
Notice how the error tells us directly what we can't do, change the item assignment!
Something we can do is concatenate strings!
In [27]:
s
Out[27]:
'Hello World'
In [28]:
# Concatenate strings!
s + ' concatenate me!'
Out[28]:
'Hello World concatenate me!'
In [29]:
# We can reassign s completely though!
s = s + ' concatenate me!'
In [30]:
print(s)
Hello World concatenate me!
In [31]:
s
Out[31]:
'Hello World concatenate me!'
We can use the multiplication symbol to create repetition!
In [32]:
letter = 'z'
In [33]:
letter*10
Out[33]:
'zzzzzzzzzz'

Basic Built-in String methods

Objects in Python usually have built-in methods. These methods are functions inside the object (we will learn about these in much more depth later) that can perform actions or commands on the object itself.
We call methods with a period and then the method name. Methods are in the form:
object.method(parameters)
Where parameters are extra arguments we can pass into the method. Don't worry if the details don't make 100% sense right now. Later on we will be creating our own objects and functions!
Here are some examples of built-in methods in strings:
In [34]:
s
Out[34]:
'Hello World concatenate me!'
In [35]:
# Upper Case a string
s.upper()
Out[35]:
'HELLO WORLD CONCATENATE ME!'
In [36]:
# Lower case
s.lower()
Out[36]:
'hello world concatenate me!'
In [37]:
# Split a string by blank space (this is the default)
s.split()
Out[37]:
['Hello', 'World', 'concatenate', 'me!']
In [38]:
# Split by a specific element (doesn't include the element that was split on)
s.split('W')
Out[38]:
['Hello ', 'orld concatenate me!']
There are many more methods than the ones covered here. Visit the Advanced String section to find out more!

Print Formatting

We can use the .format() method to add formatted objects to printed string statements.
The easiest way to show this is through an example:
In [39]:
'Insert another string with curly brackets: {}'.format('The inserted string')
Out[39]:
'Insert another string with curly brackets: The inserted string'
We will revisit this string formatting topic in later sections when we are building our projects!

String Formatting

String formatting lets you inject items into a string rather than trying to chain items together using commas or string concatenation. As a quick comparison, consider:
player = 'Thomas'
points = 33

'Last night, '+player+' scored '+str(points)+' points.'  # concatenation

f'Last night, {player} scored {points} points.'          # string formatting


There are three ways to perform string formatting.
  • The oldest method involves placeholders using the modulo % character.
  • An improved technique uses the .format() string method.
  • The newest method, introduced with Python 3.6, uses formatted string literals, called f-strings.
Since you will likely encounter all three versions in someone else's code, we describe each of them here.

Formatting with placeholders

You can use %s to inject strings into your print statements. The modulo % is referred to as a "string formatting operator".
In [1]:
print("I'm going to inject %s here." %'something')
I'm going to inject something here.
You can pass multiple items by placing them inside a tuple after the % operator.
In [2]:
print("I'm going to inject %s text here, and %s text here." %('some','more'))
I'm going to inject some text here, and more text here.
You can also pass variable names:
In [3]:
x, y = 'some', 'more'
print("I'm going to inject %s text here, and %s text here."%(x,y))
I'm going to inject some text here, and more text here.

Format conversion methods.

It should be noted that two methods %s and %r convert any python object to a string using two separate methods: str() and repr(). We will learn more about these functions later on in the course, but you should note that %r and repr() deliver the string representation of the object, including quotation marks and any escape characters.
In [4]:
print('He said his name was %s.' %'Fred')
print('He said his name was %r.' %'Fred')
He said his name was Fred.
He said his name was 'Fred'.
As another example, \t inserts a tab into a string.
In [5]:
print('I once caught a fish %s.' %'this \tbig')
print('I once caught a fish %r.' %'this \tbig')
I once caught a fish this 	big.
I once caught a fish 'this \tbig'.
The %s operator converts whatever it sees into a string, including integers and floats. The %d operator converts numbers to integers first, without rounding. Note the difference below:
In [6]:
print('I wrote %s programs today.' %3.75)
print('I wrote %d programs today.' %3.75)
I wrote 3.75 programs today.
I wrote 3 programs today.

Padding and Precision of Floating Point Numbers

Floating point numbers use the format %5.2f. Here, 5 would be the minimum number of characters the string should contain; these may be padded with whitespace if the entire number does not have this many digits. Next to this, .2f stands for how many numbers to show past the decimal point. Let's see some examples:
In [7]:
print('Floating point numbers: %5.2f' %(13.144))
Floating point numbers: 13.14
In [8]:
print('Floating point numbers: %1.0f' %(13.144))
Floating point numbers: 13
In [9]:
print('Floating point numbers: %1.5f' %(13.144))
Floating point numbers: 13.14400
In [10]:
print('Floating point numbers: %10.2f' %(13.144))
Floating point numbers:      13.14
In [11]:
print('Floating point numbers: %25.2f' %(13.144))
Floating point numbers:                     13.14
For more information on string formatting with placeholders visit https://docs.python.org/3/library/stdtypes.html#old-string-formatting

Multiple Formatting

Nothing prohibits using more than one conversion tool in the same print statement:
In [12]:
print('First: %s, Second: %5.2f, Third: %r' %('hi!',3.1415,'bye!'))
First: hi!, Second:  3.14, Third: 'bye!'

Formatting with the .format() method

A better way to format objects into your strings for print statements is with the string .format() method. The syntax is:
'String here {} then also {}'.format('something1','something2')

For example:
In [13]:
print('This is a string with an {}'.format('insert'))
This is a string with an insert

The .format() method has several advantages over the %s placeholder method:

1. Inserted objects can be called by index position:

In [14]:
print('The {2} {1} {0}'.format('fox','brown','quick'))
The quick brown fox

2. Inserted objects can be assigned keywords:

In [15]:
print('First Object: {a}, Second Object: {b}, Third Object: {c}'.format(a=1,b='Two',c=12.3))
First Object: 1, Second Object: Two, Third Object: 12.3

3. Inserted objects can be reused, avoiding duplication:

In [16]:
print('A %s saved is a %s earned.' %('penny','penny'))
# vs.
print('A {p} saved is a {p} earned.'.format(p='penny'))
A penny saved is a penny earned.
A penny saved is a penny earned.

Alignment, padding and precision with .format()

Within the curly braces you can assign field lengths, left/right alignments, rounding parameters and more
In [17]:
print('{0:8} | {1:9}'.format('Fruit', 'Quantity'))
print('{0:8} | {1:9}'.format('Apples', 3.))
print('{0:8} | {1:9}'.format('Oranges', 10))
Fruit    | Quantity 
Apples   |       3.0
Oranges  |        10
By default, .format() aligns text to the left, numbers to the right. You can pass an optional <,^, or > to set a left, center or right alignment:
In [18]:
print('{0:<8 span=""> | {1:^8} | {2:>8}'.format('Left','Center','Right'))
print('{0:<8 span=""> | {1:^8} | {2:>8}'.format(11,22,33))
Left     |  Center  |    Right
11       |    22    |       33
You can precede the aligment operator with a padding character
In [19]:
print('{0:=<8 span=""> | {1:-^8} | {2:.>8}'.format('Left','Center','Right'))
print('{0:=<8 span=""> | {1:-^8} | {2:.>8}'.format(11,22,33))
Left==== | -Center- | ...Right
11====== | ---22--- | ......33
Field widths and float precision are handled in a way similar to placeholders. The following two print statements are equivalent:
In [20]:
print('This is my ten-character, two-decimal number:%10.2f' %13.579)
print('This is my ten-character, two-decimal number:{0:10.2f}'.format(13.579))
This is my ten-character, two-decimal number:     13.58
This is my ten-character, two-decimal number:     13.58
Note that there are 5 spaces following the colon, and 5 characters taken up by 13.58, for a total of ten characters.
For more information on the string .format() method visit https://docs.python.org/3/library/string.html#formatstrings

Formatted String Literals (f-strings)

Introduced in Python 3.6, f-strings offer several benefits over the older .format() string method described above. For one, you can bring outside variables immediately into to the string rather than pass them as arguments through .format(var).
In [21]:
name = 'Fred'

print(f"He said his name is {name}.")
He said his name is Fred.
Pass !r to get the string representation:
In [22]:
print(f"He said his name is {name!r}")
He said his name is 'Fred'

Float formatting follows "result: {value:{width}.{precision}}"

Where with the .format() method you might see {value:10.4f}, with f-strings this can become {value:{10}.{6}}
In [23]:
num = 23.45678
print("My 10 character, four decimal number is:{0:10.4f}".format(num))
print(f"My 10 character, four decimal number is:{num:{10}.{6}}")
My 10 character, four decimal number is:   23.4568
My 10 character, four decimal number is:   23.4568
Note that with f-strings, precision refers to the total number of digits, not just those following the decimal. This fits more closely with scientific notation and statistical analysis. Unfortunately, f-strings do not pad to the right of the decimal, even if precision allows it:
In [24]:
num = 23.45
print("My 10 character, four decimal number is:{0:10.4f}".format(num))
print(f"My 10 character, four decimal number is:{num:{10}.{6}}")
My 10 character, four decimal number is:   23.4500
My 10 character, four decimal number is:     23.45
If this becomes important, you can always use .format() method syntax inside an f-string:
In [25]:
num = 23.45
print("My 10 character, four decimal number is:{0:10.4f}".format(num))
print(f"My 10 character, four decimal number is:{num:10.4f}")
My 10 character, four decimal number is:   23.4500
My 10 character, four decimal number is:   23.4500
For more info on formatted string literals visit https://docs.python.org/3/reference/lexical_analysis.html#f-strings
That is the basics of string formatting!

Python Challenges Program

Challenges program: program 1: #Input :ABAABBCA #Output: A4B3C1 str1="ABAABBCA" str2="" d={} for x in str1: d[x]=d...