Last active
January 3, 2019 00:54
-
-
Save krlozadan/4712d58debbe565813e049af149a1511 to your computer and use it in GitHub Desktop.
Python Language Basics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
####################################################################### | |
# Python mathematical operators | |
2 + 2 # Sum | |
2 - 2 # Substraction | |
2 * 2 # Multiplication | |
2 / 2 # Division (Always returns a float) | |
2 // 2 # Division (Returns an int loosing the decimal part) | |
2 ** 2 # Power | |
####################################################################### | |
# Python data types | |
# The type() function will return thje type of variable or value | |
print(type(91)) # int | |
print(type(91.0)) # float | |
print(type('hello')) # str | |
print(type(True)) # bool (Notice the capital T or F for False) | |
# Data Structures | |
# Mutable (Lists and Dictionaries) | |
print(type([1,'2',10.9])) # list | |
print(type({ 'hello':'world', 'number' : 12 })) # dict | |
# Unmutable (Tuples and Sets) | |
print(type(('hello', 'world', 12 ))) # tuple | |
print(type({ 'hello', 'word', 12 })) # set | |
# Ordering, Lists and Tuples are ordered where Dictionaries and Sets aren't | |
# Duplication: Lists and Tuples allow having the same value repeated, dictionaries and sets won't allow that | |
set_duplication_example = { 2,2,2,2,2,2 } | |
print(set_duplication_example) # This will still be a set but will have the value {2} | |
####################################################################### | |
# Variable declaration: Variables can be redeclared or redefined dynamically, as python is not static typed. Just like JavaScript | |
my_string = 2 | |
my_string = 'Hello World' # Strings can be created using single or doubel quotes | |
# This would work | |
####################################################################### | |
# Indexing strings | |
# You can use indexes to acces characters of a string | |
print(my_string[1]) # Indexex start at 0 | |
# You can use reverse indexes as well, so the last character independenlty of how long the string is... will be -1 | |
print(my_string[-1]) # This will output 'd' | |
# Slicing strings (substrings) | |
alphabet = 'abcdefg' | |
# Use the square brackets with a colon to indicate start and excluded ending index | |
# Examples: | |
print(alphabet[2:5]) # output: cde | |
print(alphabet[:5]) # output: abcde | |
print(alphabet[2:]) # output: cdefg | |
print(alphabet[:]) # output: abcdefg | |
print(alphabet[2:-2]) # output: cde (you can use revserve indexing) | |
# Step size would be the third parameter in the slicing syntax. default value is 1 | |
print(alphabet[::]) # output: abcdefg | |
print(alphabet[::2]) # output: aceg | |
print(alphabet[2::2]) # output: ceg | |
# This is a nice trick to reverse a stirng | |
print(alphabet[::-1]) # output: gfedcba | |
# You can reassign list values like this | |
l = [1, 2, 3, 4, 5, 6] | |
l[2:4] = [100, 200] | |
print(l) # [1, 2, 100, 200, 5, 6] | |
####################################################################### | |
# String properties and methods | |
# String are not index assignable because they are unmutable | |
name = 'Sam' | |
# This will throa an error | |
# name[0] = 'P'' | |
# You can concatenate strings using the plus sign | |
full_name = name + ' ' + 'Jhonson' | |
# You can multiply a string as well | |
sleeping = 'z' * 10 # zzzzzzzzzz | |
# String methods | |
full_name.upper() # This willnot modify the original string value | |
full_name.lower() # This willnot modify the original string value | |
full_name.split() # Sepparate the string per white space by default, if not... with the provided parameter | |
# Multiline string | |
multiline = """ | |
Hello, this | |
is a | |
multiline | |
string that would auto-escape the ' character | |
""" | |
####################################################################### | |
# String interpolation (without using concatenation) | |
si = 'Hello, my name is {}. And I am from {}'.format(full_name, 'Mexico') | |
print(si) | |
# Another way to print strings | |
item = "ball" | |
>>> print("This is a %s" % (item)) | |
# You can use index positions | |
print('The {} {} {}'.format('fox', 'brown', 'quick')) # The fox brown quick | |
print('The {2} {1} {0}'.format('fox', 'brown', 'quick')) # The quick brown fox | |
print('The {q} {b} {f}'.format(f='fox', b='brown', q='quick')) # The quick brown fox | |
print('The {f} {f} {f}'.format(f='fox', b='brown', q='quick')) # The fox fox fox | |
# The float formatiting works as follows: "{value:width.presicion f}" | |
# width represents the white space to the left of the point | |
# Precision is how many numbers you'll see to the right of the string | |
num = 100 / 777 | |
print('The number is {n:1.3f}'.format(n=num)) | |
# This is other type of string interpolation and it is only available in python 3.6 onwards | |
print(f'The number is {num:1.3f}') | |
####################################################################### | |
# Lists are basically arrays in other languages. They can hold anydifferent types of data at the same time | |
my_list = ['one', 'two', 'three'] | |
my_list[0] # one | |
# You can use indexing and slicing just like strings | |
my_list[1:] # ['two', 'three'] | |
# One big difference with strings is that lists are mutable | |
my_list[0] = 'ONE' # Will change the list | |
# You can also add lists | |
my_list + ['four', 'five'] # ['ONE', 'two', 'three', 'four', 'five'] | |
# Some methods: | |
my_list.append('four') # Adds an item to the end of the list | |
my_list.pop() # Removes an item from the end of the list. If no index is passed, it will be the last index | |
# The following methods will perform the operation on the object itself | |
my_list.sort() # Will sort in alphabetical or numerical order. | |
my_list.reverse() # Will reverse the list order | |
####################################################################### | |
# You can access the values of a dictionary through its keys. The keys should always be strings | |
d = { 'key' : [100, 230,500], 'another_one' : 1232 } | |
d['key'][0] = 0 | |
d['yet_another_key'] = 'Hello World' | |
d.keys() # This will show all keys as a list | |
d.values() # This will return a list with all the values | |
d.items() # This will return a list of tuples | |
####################################################################### | |
# Tuples - Unmutable. similar to lists. They are very used tom maintain data integrity | |
tuple_test = (1,'one',123.0) # Can have mixed types | |
# You can use indexing, slicing and reverse indexing | |
tuple_test[0] # 1 | |
tuple_test[1:] # Returns a new tuple with the objects | |
t = ('a','a','b') | |
t.count('a') # Number of times an element is in the tuple | |
t.index('a') # Index of the first matching element | |
####################################################################### | |
# Sets | |
s = {1} | |
s.add(1) # This won't get added a second time | |
s.add(2) | |
s.add(2) # Will only add 2 once | |
# They are useful to cast a list/string and get the unique values | |
s = set([1,1,1,1,1,1,2,2,2,2,3,3,3,3]) | |
print(s) # Will output {1,2,3} | |
s = set('mississippi') | |
print(s) # Will output {'s', 'i', 'p', 'm'} | |
####################################################################### | |
# None | |
# Is a reserved keyword used to represent a null value or not a value | |
n = None # So you can declare an empty variable | |
# None is not the same as 0, False or empty string. Although None is a falsy value | |
if n: | |
print('n - True') | |
elif n == 0: | |
print('n - 0') | |
elif n == False: | |
print('n - False') | |
else: | |
print('n - None') | |
# This would print None | |
# The best way to check if a value is None would be to use the keyword 'is' | |
if n is None: | |
print('This is none') | |
# This would work but is slower due to the fact that in Python every object/variable has an ID with a value assigned to it | |
# So in this case, Python would need to check every value instead of comparing the IDs | |
if n == None: | |
print('This is none') | |
####################################################################### | |
# IO | |
# Opens a file, the first parameter represents the path and name of the file. | |
# The second parameter are options when opening. Default: 'r' for reading only. Find more about it here: https://docs.python.org/3/library/functions.html#open | |
f = open('text.txt','a+') | |
f.write('Hello World!') | |
f.write('\n') # Include a new line in the text file | |
f.write('Hello World!\n') | |
f.seek(0) # Places the cursor back to the beginning. This is useful for reading again the entire file | |
print(f.read()) # This gives you back a single string with everything in it | |
f.close() # Make sure you always close the file after using it | |
# Another syntax which doesn't require to manually close the file | |
with open('text.txt','w+') as opened_file: | |
opened_file.write('This line was insterted with another type of syntax\n') | |
opened_file.seek(0) | |
print(opened_file.readlines()) | |
####################################################################### | |
# Comparison Operators | |
# less than < | |
2 < 4 # True | |
# greater than > | |
2 > 4 # False | |
# equal == | |
2 == 4 # False | |
2.0 == 2 # True (doesn't matter the type) | |
2 == '2' # False (does matter the type) | |
# not equal != | |
2 != 2 # False | |
# less than or equal <= | |
2 <= 2 # True | |
# greater than or equal >= | |
2 >= 2 # True | |
# Chaining logical operators (In other languages would be the && or ||) | |
# Use the word 'and' to make two conditions to be true | |
1 < 2 and 3 > 2 # True | |
# Use the word 'or' to make at least one condition to be true | |
1 < 2 or 3 > 1 # True | |
# Use the keyword 'not' to get the opposite result from the logical operator | |
2 == 2 # True | |
not 2 == 2 # False | |
####################################################################### | |
# Control Flow | |
# If, Else If and Else | |
food = 'burger' | |
# Notice the colons at the end of the statement and the indentation | |
if food == 'sushi': | |
print('My favourite!!') | |
elif food == 'burger': | |
print('Ok, that was good') | |
else: | |
print('Hmm...') | |
# For Loops | |
my_list = [1,2,3,4,5] | |
# item_name represents the item over each loop run, in this case, each number in the list | |
for item_name in my_list: # This syntax is used for iterables | |
print(item_name) # This will out put every element in the list | |
# For dictionaries, the usage would be like this. | |
my_dict = {'one':1, 'two':2, 'three':3} | |
for item_key,item_value in my_dict.items(): | |
print(item_key + ' has the value ' + str(item_value)) # This will out put every element in the list | |
# The previous example was using what is called "Tuple Unpacking", here's another example | |
tu = [(1,2,3),(4,5,6),(7,8,9)] | |
for item in tu: | |
print(item) # This returns the entire tuple | |
for a,b,c in tu: | |
print(b) # This returns only the middle values, in this case: 2,5,8 | |
# While Loops | |
water_value = 0 | |
limit = 10 | |
while water_value < limit: | |
water_value += 1 | |
print(f'The current watter level is {water_value}') | |
# Loops special keywords | |
# break: will exit the current closests enclosing loop | |
# continue: goes to the top of the current closests enclosing loop | |
# pass: This will do nothing, is used as a placeholder for empty loops and functions | |
for x in range(0,3): | |
pass #this would throw and error without the pass keyword | |
def test_function(): | |
pass #this would throw and error without the pass keyword | |
####################################################################### | |
# Useful Operators | |
# Range Generator: creates a list of numbers, depending on the parameters | |
for item in range(5): # Starting 0 (default) not including 5 | |
print(item) # This will output 0,1,2,3,4 | |
for item in range(3,5): # Startint 3, not including 5 | |
print(item) # This will output 3,4 | |
for item in range(0,10,2): # Jumps every two numbers | |
print(item) # This will output 0,2,4,6,8 | |
# Enumerate: Creates an index for the specified iterable and compacts them in tuples | |
word = 'abc' | |
for item in enumerate(word): | |
print(item) # This will output: (0,a) (1,b) (2,c) | |
# Zip: crestes a list of tuples by merging lists | |
list1 = [0,1,2] | |
list2 = ['a','b','c'] | |
for item in zip(list1, list2): | |
print(item) # This will output: (0,a) (1,b) (2,c) | |
# In: check if an object is in an iterable | |
'x' in [1,3,4,'x'] # Will output True | |
# Min and Max: get minimun and maximum number in an iterable | |
numbers = [2,4,8,12,65,3] | |
min(numbers) # 2 | |
max(numbers) # 65 | |
# Random library | |
from random import shuffle | |
ordered_list = [1,2,3,4,5,6,7,8,9,10] | |
shuffle(ordered_list) # This will randomize the list, passed by reference | |
from random import randint | |
randint(0,100) # Random int between 0 and 100 (including both) | |
# Input: gets input from the user, it always returns a string | |
x = input('What is your favourite number?') | |
print(type(x)) # output: str | |
####################################################################### | |
# List Comprehension | |
# Instead of doing this to fill a list | |
list1 = [] | |
word = 'hello' | |
for letter in word: | |
list1.append(letter) # ['h','e','l','l','o'] | |
# We can use this syntax | |
# Produces the exact same result, considering that nothing else is wanted but to transform move each element to a list | |
# The first keyword, just before for... is what will be insterted upon each loop iteration | |
list2 = [letter for letter in word] # ['h','e','l','l','o'] | |
list3 = ['a' for letter in word] # ['a','a','a','a','a'] | |
list4 = [num**2 for num in range(11)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] | |
list5 = [num for num in range(11) if num % 2 == 0] # [0, 2, 4, 6, 8, 10] | |
celcius = [0, 10, 20, 32.1] | |
fahrenheit = [((9/5)*temp + 32) for temp in celcius] # [32.0, 50.0, 68.0, 89.78] | |
# if/else | |
result = [x if x %2 == 0 else 'Odd' for x in range(0,11)] # [0, 'Odd', 2, 'Odd', 4, 'Odd', 6, 'Odd', 8, 'Odd', 10] | |
# Nested for loops | |
nested = [x*y for x in [2,4,6] for y in [1,100,1000]] # [2, 200, 2000, 4, 400, 4000, 6, 600, 6000] | |
####################################################################### | |
# Functions | |
def print_name(name='World'): # This is using a default parameter | |
# This is informnation about the function, you could put the doc strings | |
''' | |
Will print the provided name | |
''' | |
print('Hello ' + name) | |
def add(n1, n2): | |
''' | |
Adds two numbers together | |
''' | |
return n1 + n2 | |
print_name('Carlos Adan') # Hello Carlos Adan | |
print_name() # Hello World | |
print(str(add(2,3))) | |
# Pig Latin exercise function (this is functional programming in practice as well, since we don't modify the original string) | |
def pig_latin(word): | |
first_letter = word[0] | |
if first_letter in 'aeiou': | |
lp_word = word + 'ay' | |
else: | |
lp_word = word[1:] + first_letter + 'ay' | |
return lp_word | |
# Multiple arguments (args and kwargs) | |
def get_percent(*args): # args is only a convention, it can be called whatever you want | |
print(args) # This will be represented as a tuple | |
return (sum(args)) * 0.1 | |
def get_fav_fruit(**kwargs): # wkargs is only a convention, it can be called whatever you want | |
print(kwargs) # This will be represented as a dictionary | |
if 'fruit' in kwargs: | |
print('My favourite frui is {}'.format(kwargs['fruit'])) | |
else: | |
print('I couldn\'t find my favourite fruit') | |
print(get_percent(5,10,90)) | |
get_fav_fruit(fruit='Kiwi', veggie='Lettuce') | |
####################################################################### | |
# Lambda expressions (Anonymous functions) | |
# Conatrsints: it is limited to single liners | |
def square(num): | |
return num ** 2 | |
my_list = [1,2,3,4,5] | |
print(list(map(square, my_list))) # [1, 4, 9, 16, 25] | |
# We can turn that into: | |
x = lambda num : num ** 2 | |
print(list(map(x, my_list))) # [1, 4, 9, 16, 25] | |
# Or: | |
print(list(map(lambda num: num ** 2, my_list))) # [1, 4, 9, 16, 25] | |
####################################################################### | |
# Variable Scope | |
var = 'Global Scope' # Global Scope | |
x = 10 | |
def func1(): | |
var = 'Enclosing Scope' # Enclosing Scope | |
global x # This will get the variable from the global scope | |
x = 20 # This is changing the global variable X | |
name = 'Enclosing Name' | |
print(var) | |
print(x) | |
def func2(): | |
var = 'This is Local' # Local Scope | |
x = 10 # This is again modifying the a local variable | |
nonlocal name # This will access the nonlocal enclosing scope | |
name = 'Enclosing name from local' | |
print(var) | |
print(x) | |
func2() | |
print(name) | |
func1() | |
print(var) | |
print(x) | |
# This would print out: | |
# Enclosing Scope | |
# 20 | |
# This is Local | |
# 10 | |
# Enclosing name from local | |
# Global Scope | |
# 20 | |
####################################################################### | |
# Object Oriented Programming (OOP) | |
class Dog(): | |
# Class Object Attributes | |
species = 'mammal' | |
# Constuctor | |
def __init__(self, breed, name, spots): | |
# This is assignment of an instance attribute | |
self.breed = breed | |
self.name = name | |
self.spots = spots | |
# Every method inm a class need to pass the parameter 'self'. Although it can be whatever name it is a convention to use self | |
def method_one(self): | |
print(self.species) | |
print(self.breed) | |
def method_two(self): | |
print(self.name) | |
# Inheritance | |
class Shape(): | |
def __init__(self): | |
pass | |
def log(self): | |
print('I am a shape') | |
# Abstract method | |
def abstract_method(self): | |
raise NotImplementedError('Subclass should implement this method') | |
class Square(Shape): | |
def __init__(self): | |
Shape.__init__(self) | |
def log(self): | |
print('I am a square') | |
class Circle(Shape): | |
def __init__(self): | |
Shape.__init__(self) | |
def log(self): | |
print('I am a circle') | |
class Triangle(Shape): | |
def __init__(self): | |
Shape.__init__(self) | |
sq = Square() | |
c = Circle() | |
t = Triangle() | |
for shape in [sq, c, t]: | |
shape.log() | |
def log_shape(shape): | |
shape.log() | |
log_shape(sq) | |
log_shape(c) | |
log_shape(t) | |
# Magic / Dunder methods | |
class Book(): | |
def __init__(self, name, author, pages): | |
self.name = name | |
self.author = author | |
self.pages = pages | |
# This is a special method used to return a string representation of the class | |
def __str__(self): | |
return f'{self.name} by {self.author}' | |
def __len__(self): | |
return self.pages | |
def __del__(self): | |
print(f'{self.name} is about to be deleted...') | |
b = Book('Python Book', 'CJ', 200) | |
print(b) | |
print(len(b)) | |
del b # Del keyword is used to delete objects from memory | |
# Dir and Help | |
# Use dir to get a list of all the methods an object has availabe | |
dir("Hello") # This will give a list of the methods available for strings. | |
# Works the same way with custom classes | |
# To get information about a specific method use the help function | |
help("hello".format) | |
# This would return information about the format method of the string object | |
# Operator Overloading | |
# This helps makes use of the logical operators such as +, -, * and / to have specific functionality to an object | |
# Example: | |
class Vector2(): | |
def __init__(self, x, y): | |
self.x = x | |
self.y = y | |
def __add__(self, another_value): | |
''' | |
This will allow to add two vector twos or a vector and a scalar value | |
''' | |
try: | |
if isinstance(another_value, Vector2): | |
return (self.x + another_value.x, self.y + another_value.y) | |
elif isinstance(another_value, int) or isinstance(another_value, float): | |
return (self.x + another_value, self.y + another_value) | |
else: | |
raise Exception("Both operands should be of type Vector 2") | |
return None | |
except Exception as e: | |
print(e) | |
v1 = Vector2(2,2) | |
v2 = Vector2(5,1) | |
print(v1) | |
res = v1 - 23 | |
if res is None: | |
print("There was an error") | |
else: | |
print(res) | |
####################################################################### | |
# Exception Handling | |
# https://docs.python.org/3/library/exceptions.html | |
while True: | |
try: | |
result = int(input('Please provide a number: ')) | |
except OSError: # This is catching a specific error type | |
print('Whoops that is not a valid number') | |
continue | |
except: # This is catching every error type | |
print('Whoops that is not a valid number') | |
continue | |
else: # This will only run if there was no error | |
print('We finished') | |
break | |
finally: # This will run even if there was an error | |
print("I'm always going to run") | |
####################################################################### | |
# Decorators | |
# Functions as objects | |
def func(): | |
print('Hello World') | |
func() # Output: Hello World | |
print(func) # Output: <function func at 0x030E07C8> | |
# This is because the function is an object, that means we can assign it to other variables | |
another_function = func | |
another_function() # Output: Hello World | |
del func | |
# func() # This will throw an error, because the poinert to that function was deleted. Python no longers know about "func" | |
another_function() # This would still work, because "another_function" is still pointing to the function "func" was pointing to | |
# Functions as arguments | |
# Since you can pass functions as arguments, a decorator is essentially adding functionality before and after the original function. | |
# Decorator function | |
def new_decorator(original_function): | |
def wrapper_function(): | |
print('Some code BEFORE the original function') | |
original_function() | |
print('Some code AFTER the original function') | |
return wrapper_function | |
# Original function | |
def func_manual_decorator(): | |
print('Running function to be decorated') | |
# First example: Manually creating a decorator | |
manual_decorated_func = new_decorator(func_manual_decorator) | |
print(manual_decorated_func) # <function new_decorator.<locals>.wrapper_function at 0x03AA9540> | |
manual_decorated_func() | |
# Second example: Using the decorator syntax | |
@new_decorator # This acts like an on/off switch, if you don't want the decorator, you just remove this line | |
def func_decorator(): | |
print('Running function to be decorated') | |
print(func_decorator) # <function new_decorator.<locals>.wrapper_function at 0x03AA9540> | |
func_decorator() | |
####################################################################### | |
# Generators | |
# They serve as a way of creating a sequence of values in a memory efficient way | |
# Instead of doing this, because it needs to store a list with every value | |
def cubes(n): | |
result = [] | |
for x in range(n): | |
result.append(x ** 3) | |
return result | |
# Do this | |
def gen_cubes(n): | |
for x in range(n): | |
yield x ** 3 | |
for num in cubes(10): | |
print(num) | |
for num in gen_cubes(10): | |
print(num) | |
# Both do the same thing but the later is way more memory efficient. If you wanted the list you could cast it: | |
num_list = list(gen_cubes(10)) | |
# Next Function | |
# next is used to get the next iteration on a iterable object | |
def simple_range(): | |
for x in range(3): | |
yield x | |
sr = simple_range() | |
print(sr) # <generator object simple_range at 0x02E88F70> | |
# This means we can then get the following value using the next function | |
print(next(sr)) | |
print(next(sr)) | |
print(next(sr)) | |
try: | |
print(next(sr)) # This will throw an error. As a tip, the for loop automatically catches that error to know where to stop | |
except: | |
print('End of generator') | |
# Iter Function | |
# Converts an object that might be an iterable to an iterator | |
iterable_string = 'hello' # Even though you can iterate over a string, it doesn't mean it is an iterator object. So the folowing line will fail | |
try: | |
print(next(iterable_string)) | |
except Exception as e: | |
print(e) | |
# This will work | |
iterator_string = iter(iterable_string) | |
try: | |
print(next(iterator_string)) | |
print(next(iterator_string)) | |
print(next(iterator_string)) | |
except Exception as e: | |
print(e) | |
####################################################################### | |
''' | |
Virtual environments allows to have dependencies for different projects in sepparate places | |
To use virtual environments you need to use pip to install 'virtualenv' | |
After the package has been installed, in the root directory of the project run the command: | |
virtualenv name_of_the_env | |
You can even define the python version the project uses | |
Make sure the environment folder doesn't get included in the version control system | |
After that depending on the OS you can activate the environment by: | |
Linuz/OSX: | |
source /name_of_the_env/bin/activate | |
Windows: | |
/name_of_the_env/Scripts/activate | |
Then you can create a requirements file with all the dependencies using | |
pip freeze < requirements.txt | |
This file can then be added to the version control. To install every dependency in a requirements.txt use: | |
pip install -r requirements.txt | |
To stop using a virtual env, use the command deactivate | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment