Python for everyone: Mastering Python The Right Way
Tags: python, beginners
Published: 2022-03-04 10:59:09

In the recent years Python has become one of the most popular programming language. This has not happened by accident, but mainly because: 

- **Its easy to learn and use** - Python has an English-like syntax, making it easier to read and understand the code. 
- **Python is free** - Python comes under the OSI approved open-source license. This makes it free to use and distribute. Who doesn't like free stuff? 
- **Improves Productivity** - We have mentioned that Python is a very simple language. Its simplicity make Developers to focus on solving the problem thus spending less time understanding the syntax or behavior of the programming language, improving productivity.
- **Libraries Support** - due to its vast application, Python standard library is huge, you can find almost all the functions needed for your task. And if you don't find, Python external libraries has over 200,000+ packages.
- **its portable** - You can run Python program in different platform(even your smartphone) without changing a single line of code to adjust to platform dependency issues. You only write once and run it anywhere.

After analyzing the above pros I can comfortably say Python is for Everyone. It is a great choice for beginners up to professionals. You still don't believe me!! Okay, lets check at the areas you can apply python programming language:
1. Big Data and data science,
2. artificial intelligence, machine learning and neural networks, 
3. physical computing (Raspberry Pi computer) and Embedded Applications
4. Web Development
5. Scripts and Automation
6. Game Development
7. Desktop GUI
8. Web Scraping Applications
9. Business Applications
10. Audio and Video Applications
 
The objective of this article is not to sell Python, the language practically sells itself, but to guide you on the core concepts you need to master before you can officially call yourself a Python GURU. Mastering this concepts will make it easier for you to venture in above Python application fields.The concepts are basics and intermediate, easy stuff.

The **basic concepts** that we will discuss are:
1. Data types - Numbers, Strings, Boolean, 
2. Python Operators - Arithmetic Operators, Comparison Operators, Boolean Operators
3. Variables and Keywords
4. Flow Control Statements - if statements, while loops, for loops
5. Function - Inbuilt Functions, defining a function, arguments, anonymous functions,  
6. Python Data Types - Lists, Tuples, Sets, Dictionaries
7. Classes and Objects, Inheritance, 
8. Handling the error and exceptions - try.. except.. else.. finally..
9. importing libraries
10. String in-depth
11. Number in-depth
12. Date and Time

The **intermediate-level** concepts that we will discuss are:
1. Regular Expressions (regexes)
2. File Operations
3. Making your own module/library



## 1.1 Data types
You need to master data types. This are category for values. In Python every value belongs to exactly one data type. You need to learn how to declare them. Most common data type in python are:

- **String** - This is a text values. Always surround your string in quotes. For Example:
`'Hello, I am learning Python'`

- **Integer** - This is any whole number, positive or negative. For Example:
```
23
-21
```

- **Float** - This is just any valid number that contains a decimal point. For Example:
```
33.341416
-575.6474562
0.425
```

- **Boolean** - this is a data type that can be one of two values: either True or False. For Example:
```
True
False
```

## 1.2 Python Operators 
Python offers many different operators for working with and comparing data types. For Example:
- **Arithmetic Operators** - This operators are for doing arithmetic; addition, subtraction, multiplication, division, and others.
```
** 	Exponent 
% 	Modulus/remainder 
// 	Integer division/floored quotient 
/ 	Division 
* 	Multiplication 
- 	Subtraction 
+ 	Addition
```

- **Comparison Operators** - This compares two values and evaluate down to a single Boolean value. For Example:

```
== 	Equal to
!= 	Not equal to
< 	Less than
> 	Greater than
<= 	Less than or equal to
>= 	Greater than or equal to
```

```
'hello' == 'hello' # True
'hello' == 'Hello' # False
```

- **Boolean Operators** - This operators compare Boolean values.
**and** - binary operator(always take two Boolean values) that evaluates an expression to True if both Boolean values are True, otherwise, it evaluates to False. For Example:  
```
True and True  	# True
True and False 	# False
False and False # False
```

**or** - binary operator that evaluates an expression to True if either of the two Boolean values is True . If both are False , it evaluates to False. For Example:
```
True or True 	# True
True or False 	# True
False or False 	# False
```

**not** - Evaluates to the opposite Boolean value. For Example:
```
not True 	# False
not False	# True
```

## 1.3 Variables and Keywords
A variable is like a box in the computer’s memory where you can store a single value that can be accessed later. We create a variable by using variable name, an equal sign (assignment operator), and the value to be stored. For Example: 
name = 'Elkanah Malonza'

Rules of creating a variable
1. It can be only one word.
2. It can use only letters, numbers, and the underscore ( _ ) character.
3. It can’t begin with a number.
4. It cannot be a keyword. keywords have special meaning in any programming language.
Here is a list of keywords in Python.

![Python Keywords](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysm3tfx898imcc5zw30p.png)

## 1.4 Flow Control Statements 
Flow control statements decides which Python instructions to execute under which conditions. Flow control statements often start with a part called the condition, and followed by a block of code called the clause. Condition are Boolean expressions that when evaluates to true execute the clause.

**1.4.1 if...elif..else statements** 
An if statement’s clause will execute if the statement’s condition is True and skipped if the condition is False.
It can be optionally followed by several **elif statement** , if you have a case where you want one of many possible clauses to execute. 
if clause can be optionally followed by an **else statement**. The else clause is executed only when the if statement’s and/or elif statement condition is False .
```
if name == 'Elkanah':
	print('Hello Elkanah')
elif name == 'Malone':
	print('Hello Malone')
else:
	print('Hello')
```

**1.4.2 while loops**
The code in a while clause will be executed over and over, as long as the while statement’s condition is True.
For Example:
```
count = 0
while count < 5:
	print('Hello, world.')
	count = count + 1
```
A **break Statements** can be used to break out program execution of a while loop’s clause early.

```
count = 0
while count < 5:
	print('Hello, world.')
	if count == 3:
		break
	count = count + 1
```
A **continue statement** causes program execution to immediately jumps back to the start of the loop and reevaluates the loop’s condition.

```
count = 0
while count < 5:
	count = count + 1
	if count == 3:
		continue
	print(count)
```

**1.4.3 for loops and the range() Function**
For loops are used to execute a block of code only a certain number of times.
```
for i in range(10):
	print('Malone Ten Times')
```

## 1.5 Function
Functions provide a way to compartmentalize your code into small tasks that can be called from multiple places within an app. It also make you avoid duplicating code.

**1.5.1 Inbuilt Functions** 
This are function that are provided by python by default. Example:

```
print('I love Python')
name = input("Enter Your Name: ")
print(name)
len(name)
```
All in in-built functions in Python 3.7

![In-built functions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ri0ry17own7zqbiwd0g.png)
**1.5.2 Defining a function**
You can also define your own functions
```
def intro():
	print("Hello Stranger.")
	print("I love Python.")

intro()
```

**1.5.3 Function with arguments**
- You can also define your own functions that accept arguments.  

```
def add(x,y):
	z = x + y
	print(z)

add(3,8) # 11
```

- Return Values and return Statements
```
def add(x,y):
	return x + y

add(2,3) # 5
```

- Defining optional parameters with defaults
```
def add(x=0,y=0):
	return x + y

add() # 0
add(4) # 4
add(2,3) # 5
```

**1.5.4 Using keyword arguments (kwargs)**
You can tell the function which parameter will have what value by using the syntax parameter = value in the code that’s calling the function.

```
def divide(x,y):
	return x/y

divide(y=2, x=3) # 1.5
divide(x=2, y=3) # 0.6666666666666666
```

**1.5.5 *args - Passing in an arbitrary number of arguments**
You can also design the function so that it accepts any number of arguments, use `*args` as the parameter name.
Whatever you pass in becomes a tuple named `args` inside the function. A tuple is an immutable list (a list you can’t change).

```
def sorter(*args):
	newlist = list(args)
	# Sort and show the list.
	newlist.sort()
	return newlist

sorter(2, 0.42, -42,4.24, 25, 5)
```

**1.5.6 Anonymous Functions/lambda functions.**
The anonymous because function doesn’t need to have a name.
`Syntax: Lambda arguments : expression`

```
percent = lambda n : f"{n:.2%}"
print(percent(.6)) # 60.00%
```

## 1.6 Python Data Structures
**1.6.1 Lists**
A list is a value that contains multiple values in an ordered sequence. A list begins with an opening square bracket and ends with a closing square bracket, []. Values inside the list are also called items which are separated with commas. Example:

```
subjects = ['Maths', 'Physics', 'Biology', 'Geography', 'History']
num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
```

To get individual values in a List we use Indexes. Example:

```
subjects = ['Maths', 'Physics', 'Biology', 'Geography', 'History']
print(subjects[0]) # Maths 
print(subjects[0]) # Physics 
```

List have methods like `append()`, `insert()`, `pop()`, `remove()`... etc, that can be of use when writing python code. You need to master all of them. 

**1.6.2 Tuples**
A tuple is just an immutable list. In other words, a tuple is a list, but after it’s defined you can’t change it. 
Tuples are typed with parentheses, ( and ) , instead of square brackets, [ and ].

```
subjects = ('History', 'Geography', 'Biology', 'Physics', 'Maths')
num = (5, 7, 8, 5, 3, 8, 5, 2, 1, 8, 5, 7)
```
List methods and techniques that modified list data won't work with tuple but the rest will.


**1.6.3 Sets**
Python Sets is also a means of organizing data. The difference between a set and a list is that the items in set have no specific order. Even though you may define the set with the items in a certain order, none of the items get index numbers to identify their positions.

To define a set, use curly braces where you would have used square brackets  for a list and parentheses for a tuple. For example:

```
subjects = {'Maths', 'Physics', 'Biology', 'Geography', 'History'}
num = {5, 7, 8, 5, 3, 8, 5, 2, 1, 8, 5, 7}
```

You can’t change the order of items in a set, so you cannot use `.sort()` to sort the set or `.reverse()` to reverse its order. 

**1.6.1 Dictionaries**
Like a list, a dictionary is a collection of many values, but unlike indexes for lists, indexes for dictionaries can use many different data types, not just integers. 
Indexes for dictionaries are called keys, and a key with its associated value is called a key-value pair.
In code, a dictionary is typed with braces, {}. Example:

```
person = {
    "name": "Elkanah",
    "gender": "Male",
    "height": "5.9 Foot",
    "weight": "67 kg",
}
```

You can access these values through their keys:

```
print(person["name"]) # Elkanah
print(person["height"]) # 5.9 Foot
```

Like lists, Dictionaries too have methods for instance `clear(), copy(), fromkeys(), get(), items(), keys(), pop(), popitem(), setdefault(), update()` and  `values()` . This methods are used to manage data in a Dictionary. You need to know how to use them.

## 1.7 Classes and Objects, Inheritance 
Like functions, classes also allow you to compartmentalize code and data. 
**Class** - A piece of code from which you can generate a unique object, where each object is a single instance of the class. 
**Attribute** - A characteristic of an object that contains information about the object. 
**Method** - A Python function that’s associated with the class. It defines an action that object can perform. 
Example:

```
class Dog:
    def __init__(self, age, name):
        self.age = age
        self.name = name

    def change_name(self, new_name):
        self.name = new_name

    def display_name(self):
        print(self.name)

    def display_age(self):
        print(self.age)


puppy = Dog(3, 'TOM')
puppy.display_age()
puppy.display_name()
puppy.change_name("Cindy")
puppy.display_name()
```

**Inheritance**
inheritance is defined by creating sub-classes within a class.
**Syntax:**
```
class parent:
   statements
class child(parent):
   statements
```

Sub-classes inherit all the attributes and methods of some higher-level main class, or parent class, which is usually referred to as the base class.

```
class Quadrilateral:
    def __init__(self, a, b, c, d):
        self.a = a
        self.b = b
        self.c = c
        self.d = d

    def perimeter(self):
        p = self.a + self.b + self.c + self.d
        print("perimeter: ", p)


q1 = Quadrilateral(4, 5, 7, 9)
q1.perimeter()


class Rectangle(Quadrilateral):
    def __init__(self, a, b):
        super(Rectangle, self).__init__(a, b, b, a)

    def area(self):
        area = self.a * self.b
        print("Area:", area)


r1 = Rectangle(20, 10)
r1.perimeter()
r1.area()
```

## 1.8 Handling the error and exceptions - try..except..else..finally
Getting an error, or exception, in your Python program means the entire program will crash. You don’t want this to happen in real-world programs. Example:
`dummy_file = open('random_file.csv')`
`# FileNotFoundError: [Errno 2] No such file or directory: 'random_file.csv'`

Above program creates a `FileNotFoundError` and stops executing. We want the program to detect errors, handle them, and then continue to run. That's where `try...except...else...finally...` Statements comes in.

```
try:
    # Open file and shows its name.
    dummy_file = open('random_file.csv')
    print(dummy_file.name)
except Exception:
    print("Sorry, File named random_file.csv Does not Exist.")
```

- _Being Specific about Exceptions_
Sometimes we need to catch a specific error. For Instance, `FileNotFoundError` in above code. You add the exception name after the except statement.

```
try:
    # Open file and shows its name.
    dummy_file = open('random_file.csv')
    print(dummy_file.name)
except FileNotFoundError:
    print("Sorry, File named random_file.csv Does not Exist.")
```

- _One Try statement can be followed by multiple except statement._

```
try:
    ...
except FileNotFoundError:
    print("Sorry, File named random_file.csv Does not Exist.")
except Exception as e:
    print(e)
```

- _else block_  
Code in this block will be executed if no exceptions raised 

```
try:
    ...
except FileNotFoundError:
    print("Sorry, File named random_file.csv Does not Exist.")
except Exception as e:
    print(e) 
else:
    # Continue on here only if no exceptions raised

```
- _finally block_
if included, the code in this block will run whether an exception occurs or not.

```
try:
    try to do this
except:
    if x happens, stop here
except Exception as e:
    if something else bad happens, stop here
else:
    if no exceptions, continue on normally here
finally:
    do this code no matter what happened above
```


## 1.9 Importing libraries
Python comes with a set of modules called the **standard library** - which is a Python program that contains a related group of functions that can be embedded in your programs. Before you can use the functions in a module, you must import the module with an import statement.
**Example:** the random module has random number–related functions,

```
import random

for i in range(15):
    print(random.randint(1, 10))
```

**Example:** the math module has mathematics related functions

```
import math

print(math.sqrt(81))
```


## 1.10 String In-depth
In data types you learnt about string data type. In python, You can do more with strings other than write, print, and access strings. You can extract partial strings from string values, add or remove spacing, convert letters to lowercase or uppercase, check that strings are formatted correctly, etc. This is easily done by use of different string method, indexes and slices and other in-built functions. Example of indexes, slices and in-built functions.
`s[i:j:k]` - A slice of s from i to j with step k.
`min(s)` - The smallest (lowest) item of string s, uses Ascii (space is smaller than a-z,A-Z)
`max(s)` - The largest (highest) item of string s.

Their are over 30 string methods in python. They will come in handy if you know how to use them. Here are a few of them:

```
'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'
```

## 1.11 Numbers in-depth
You can also do more with int and float Data types other than declaring them and doing arithmetic operation on them. Below are in-built function that can manipulate Numbers in python.
- **abs(x)** - Returns the absolute value of number x (converts negative numbers to positive)
- **bin(x)** Returns a string representing the value of x converted to binary.
- **float(x)** Converts a string or number x to a the float data type
- **format(x,y)** - Returns x formatted as directed by format string y.
- **hex(x)** - Returns a string containing x converted to hexadecimal, prefixed with 0x.
- **int(x)** - Converts x to the integer data type by truncating (not rounding) the decimal point and any digits after it.
- **max(x,y,z ...)** - Takes any number of numeric arguments and returns whichever one is the largest.
- **min(x,y,z ...) ** - Takes any number of numeric arguments and returns whichever one is the smallest.
- **oct(x)** - Converts x to an octal number, prefixed with 0o to indicate octal.
- **round(x,y)** - Rounds the number x to y number of decimal places.

If you want to do complex math operation on numbers like trigonometry, hyperbolic, powers and logarithms, angular conversions, constants like pi and e, import the math module. Below are some of the methods and attributes of math module:

```
'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc'
```

## 1.12 Date and time
To work with dates and times, you typically need to use the datetime module.
- Import the datetime module with nickname dt*
`import datetime as dt`

**1.12.1 Working with Dates**
- A date consisting of month, day, and year (no time information).
`variable = datetime.date(year, month, day)`
- Store today's date in a variable named today.*
`today = dt.date.today()`
- Store some other date in a variable called birth_date*
birth_date = dt.date(2019, 12, 31)
- Accessing Month, Day and Year

```
print(birth_date.month)
print(birth_date.day)
print(birth_date.year)
```
**1.12.2 Working with times**
- A time consisting of hour, minute, second, microsecond, and optionally time zone information if needed (but no date).
- If you want to work strictly with time data, use the `datetime.time` class. The basic syntax for defining a time object using the time class is 
`variable = datetime.time([hour,[minute,[second,[microsecond]]]])`
- all the arguments are optional

```
midnight = dt.time() # 00:00:00
just_morning = dt.time(06,09,00)
```

**1.12.3 Working with date and time**
- A single item of data that includes date, time, and optionally time zone information.
`variable = datetime.datetime(year, month, day, hour, [minute, [second, [microsecond]]])`
- The month, day, and year are required. The rest are optional and set to zero in the time if you omit them.

```
import datetime as dt
new_years_eve = dt.datetime(2019,12,31,23,59)
print(new_years_eve)
```

**1.12.4 Formatting Strings for Dates and Times**
The default date display is yyyy-mm-dd, but you can format dates and times however you want using f-strings. Learn how to use the right directives in f-strings and you will display date and time the way you like. Example:

```
print(f"{birth_date:%A, %B %d, %Y}")
today_s_date = f"{today:%m/%d/%Y}"
print(today_s_date) # 03/03/2022
```
**
1.12.5 Time Delta**
- The `timedelta` happens automatically when you subtract one date from another to get the time between.

```
new_year = dt.date(2022, 1, 1)
birth_day = dt.date(2022, 5, 27)
days_between = birth_day - new_year
```

- You can also define any timedelta (duration) using this syntax:
`datetime.timedelta(days=, seconds=, microseconds=, milliseconds=, minutes=, hours=, weeks=)`
If you omit an argument, its value is set to zero.
```
import datetime as dt
new_years = dt.date(2022,1,1)
duration = dt.timedelta(days=146)
print(new_year + duration) # 2022-05-27
```

```
import datetime as dt
now = dt.datetime.now()
birthdatetime = dt.datetime(1997, 1, 19, 6, 00)
age = now - birthdatetime
print(age) # 9174 days, 15:13:05.474595
print(type(age)) # <class 'datetime.timedelta'>

```

## 2. Intermediate Python 
### 2.1 Regular Expressions (regexes)
Regular expressions are huge time-savers for programmers. They allow you to specify a pattern of text to search for or filter. 
- All the regex functions in Python are in the re module.
`import re`

- Passing a string value representing your regular expression to `re.compile()` returns a Regex pattern object
- A Regex object’s method `search()` looks for the first instance, `findall()` looks for all matching instance and
the sub() method for substituting all matching strings
 with string specified.
**Example:** Matching Kenya Phone Numbers (+254)712345678 | 0765-432-123 | 0722004445

```
import re

def extract_phone_num(text):
    kenya_pattern = r"(\(\+\d{3}\)\d{9})|(\d{4}-\d{3}-\d{3})|(\d{10})"
    matching = re.compile(kenya_pattern)
    return matching.findall(text)


my_text = "(+254)734423363 0714-134-941This is 0756464654 just a text with random 0756464654 Kenyan Phone Numbers " \
          "(+254)718306114 0718-306-114 blah 0756464654 blah 07013-213-311 0756464654"
print(extract_phone_num(my_text))
```
Result:
`[('(+254)734423363', '', ''), ('', '0714-134-941', ''), ('', '', '0756464654'), ('', '', '0756464654'), ('(+254)718306114', '', ''), ('', '0718-306-114', ''), ('', '', '0756464654'), ('', '7013-213-311', ''), ('', '', '0756464654')]`

Now that you know the basic steps for creating and finding regular expression objects with Python. You need to learn some more powerful pattern-matching capabilities. Learn the regex symbols used in patterns. For Instance: `r"(\(\+\d{3}\)\d{9})|(\d{4}-\d{3}-\d{3})|(\d{10})"`. Learn how to make your search Case-sensitive and substituting strings matched. 
 
### 2.2 File Operations
File Operations involves how to use Python to create, read, and save files on the hard drive. The files can be both text or binary files. It also involves organize preexisting files on the hard drive For Instance: copying, renaming, moving, or compressing them.
**File Paths**
But before you learn how to code file operations, you should be comfortable working with file paths in Python. The `path` module in `os` module makes it simple to work with file paths.
The `os.path` methods and attributes that make it easy to work with files paths are: 

```
'abspath', 'altsep', 'basename', 'commonpath', 'commonprefix', 'curdir', 'defpath', 'devnull', 'dirname', 'exists', 'expanduser', 'expandvars', 'extsep', 'genericpath', 'getatime', 'getctime', 'getmtime', 'getsize', 'isabs', 'isdir', 'isfile', 'islink', 'ismount', 'join', 'lexists', 'normcase', 'normpath', 'os', 'pardir', 'pathsep', 'realpath', 'relpath', 'samefile', 'sameopenfile', 'samestat', 'sep', 'split', 'splitdrive', 'splitext', 'stat', 'supports_unicode_filenames', 'sys'
```
Learn how to work with above attributes and methods.
Their are others `os` methods apart from those found in `os.path` that used to manage files and file paths. Example:
- `os.getcwd()` - get current working directory
- `os.chdir(<path>)` - change directory
- `os.makedirs(<path>)` - create new folder/directory
- `os.listdir(path) ` - returns a list of filename strings for each file in the path argument.

**The File Reading/Writing Process**
If you are comfortable working with folders and file paths, lets specify the location of files to read and write.
The following are functions for opening, reading and writing **Text** files.
- **open()** - function to return a File object. default read mode
- **open('<file 2 open>', 'w')** - open file for writing. Replace 'w' with 'a' to open file in append mode.
- **read()** - method on the File object to read its content.
- **readlines()** - method to get a list of string values from the file, one string for each line of text.
- **write(<text to write/append>)** - method on the File object to write content.
- **close()** - Close the file by calling the method on the File object.
Example: 

```
file_x = open('/users/path_to_folder/my_file.txt')
file_x.readlines()
file_x.close()
file_x = open('/users/path_to_folder/my_file.txt', 'w')
file_x.write('Hello world!\n') 
file_x.close()
```

**shelve Module**
You can save variables in your Python programs to binary shelf files using the shelve module.

```
# Save
shelfFile = shelve.open(<filename>)
cats = ['Zophie', 'Pooka', 'Simon']
shelfFile['cats'] = cats
shelfFile.close()
# Open
shelfFile = shelve.open('mydata')
shelfFile['cats']
# ['Zophie', 'Pooka', 'Simon']
shelfFile.close()
```

**Organizing File**
`import shutil # shell Utility`
- **shutil.copy('source', 'destination')** - will copy a single file
- **shutil.copytree(source, destination)** - will copy the folder with all of its files and sub-folders
- **shutil.move(source, destination)** - will move file from source to destination.
- **os.unlink(path)** - will delete the file at path .
- **os.rmdir(path)** - will delete the folder at path . This folder must be empty of any files or folders.
- **shutil.rmtree(path)** - will remove the folder at path , and all files and folders it contains will also be deleted

- Safe Deletes with the `send2trash` Module
```
import send2trash
send2trash.send2trash('bacon.txt')
```
**Walking THROUGH a Directory Tree**
- **os.walk(<file_path>)** - will return three values on each iteration through A for loop
1. A string of the current folder’s name
2. A list of strings of the folders in the current folder
3. A list of strings of the files in the current folder
Example: 

```
import os

for folderName, subfolders, filenames in os.walk('/home/malone/PycharmProjects'):
    print('The current folder is ' + folderName)
    for subfolder in subfolders:
        print('SUBFOLDER OF ' + folderName + ': ' + subfolder)
        for filename in filenames:
            print('FILE INSIDE ' + folderName + ': ' + filename)
            print('')
```
## 2.3 Making your own module/library
We have already mentioned that modules are collections of pre-written code that you can `import` and use in your own code.
A module is just a file with a .py filename extension. The name of the module is the same as the filename without the `.py` file extension. Yeah, it is that simple.

Example if I have a python file named `email_app.py`, inside the file are function like send_email(), inbox(), sent_box() and drafts() and Global Variables like EMAIL and PORT. I can import this module as:

```
import email_app
email_app.inbox()
print(email_app.PORT)
```

## Conclusion
After going through the above Python concepts and learning them in details (I was just pointing them out, I didn't go into details), you will find it easy for you to venture in Data Science, Web Development and Other Python fields without a hustle. Their are some interesting topics like Web Scrapping, Scheduling Tasks and Launching Programs, Creating and manipulating binary files(PDFs, Word Doc, Excel, CSV Files), Network Programming, Sending Emails and Manipulating Images that I have left out. This topics are easy because all you do is import the respective module and working with their methods and attributes. But if you have not mastered the basics, they will definitely be hard.