Fundamentals of Python Programming for Beginners

Nikita Prasad 17 Jul, 2024
14 min read

Introduction

If you’ve been in the data field for quite some time, you’ve probably noticed that some technical skills are becoming more dominant, and the data backs this up. Until the release of NumPy in 2005, Python was considered slow for numeric analysis. But Numpy changed that. Pandas, in 2008, made Python the best language for Data Analysis.

Further, with the introduction of frameworks like SciKit-Learn, Tensorflow, and PyTorch—Python became the number one programming language for Data Science (AI and ML).

Well, if you had asked any data professional a few years ago which language you should learn, R or Python, most would have said it really doesn’t matter. But with the rise in AI and LLMs, Python is certainly dominating. Today, in this part, we will be going over the handful of useful and cool tips and tricks you need to ditch the noob Python programmer inside you and write some better code. These are the fundamentals of Python programming for writing better codes, whether you are a beginner or a seasoned expert.

Python Programming for Beginners

Learning Objective

The goal of this Fundamentals of Python Programming article is to make sure whenever you’re reading the production code:

  1. You know the Python concepts firmly
  2. You understand what’s happening in the production-level codes
  3. You can reproduce the code and write your features that other team members understand

There are many codes, so I compiled all of them in a Python notebook, which you can download here. These codes will serve as a quick syntax reference.

Before diving deep first, let’s address the elephant in the room: Why Python?

Why You Should Master Python?

Do you know 87% of data scientists use Python as their main language for current projects, and another 10% say they use it as a secondary language? That’s a huge number. Nowadays, many academic and research work and most enterprises extensively utilize Python programming language in Gen-AI and Deep Learning, Data Science, Data Analysis, Web Development, Web Scraping, etc. Python is often the language of choice for AI and machine learning applications due to several key reasons:

  • Easy to Learn Programming Language: Compared with CPP/Java, etc., it has a pretty straightforward and easy-to-understand syntax and is suitable for beginners.
  • Variety of Libraries: It also has a rich set of built-in functions like print(), list(), str(), etc., and libraries like NumPy, Pandas, Scikit-Learn, etc., to simplify complex tasks.
  • Enthusiastic Community Support: Stuck with a problem? Don’t worry; the Python community is just a browser search away.

Disclaimer: Python is a case-sensitive programming language. The convention is to avoid syntax errors using a snake case with all lowercase letters.

I’ll start with the most important crux of Fundamentals of Python Programming, gradually working our way up. 

This is going to be very code-y, but stay with me. Let’s begin!

Python for Data Science Projects

Python Fundamentals

The coming section will talk about the Python fundamentals:

Static Vs. Dynamic Typing

  • Static Typing: In this, the methods to be invoked or properties to be accessed are determined at the time of compilation, enhancing datatype safety and reducing time complexity.
# Static Typing in CPP, etc
int q = 9
  • Dynamic Typing: In this, the variable’s datatype is determined at program runtime, allowing variables to change types easily.
# Dynamic Typing in Python
a = 1
print(type(a))
b = "Hi"
print(type(b))
c:float = 3.14
print(type(c))Output

Output

<class 'int'>

<class 'str'>

<class 'float'>

Static Vs. Dynamic Binding

  • Static Binding: Also known as Early Binding, this allows the methods to be invoked to be determined at the compile time, leading to faster execution and type safety, as it doesn’t store any other datatype in the same variable once it is assigned.
  • Dynamic Binding: Also known as Late Binding, this allows the methods to be invoked to be determined at run-time, making it more flexible and polymorphic. It stores any other datatype in the same variable in the same program.
# Dynamic binding in python
a = 1
print(a)
a = "Hi"
print(a)

Output

1

Hi

Compilation in Programming Languages

Compilation is a widely used but poorly understood concept, especially by beginners. It converts high-level language code into machine-level binary code.

It’s done using:

  • Compiler: Programming languages like Java, CPP, and C translate all the code simultaneously before the program runs.
  • Interpreter: Programming languages like Python and PHP translate the code line-by-line as the program runs.

Also read: Everything You Ever Wanted to Know About Setting up Python on Windows, Linux and Mac

Important Keywords in Python

These are some reserved words that are used by the compiler and interpreter to understand the program and make their work easier during the compilation process.

Python Keywords

Identifiers are Not Variables

Though it seems the same, identifiers are the names we give to uniquely identify a variable, function, class, module, or other object. In contrast, the variable is a name given to a memory location used to store a value.

Having said that, since Python gives us the flexibility to name our identifiers, there are some rules associated with it:

  1. You can’t start with a digit but can end (e.g., 1identifiername is not valid).
name1 = "AnalyticalNikita.io"
print(name1)

Output

AnalyticalNikita.io
  1. It can combine uppercase and lowercase letters, digits or an underscore(_).
myVariable = 3
VariableName = 4
_my_variable = 5
_ = "AnalyticalNikita.io"

print(myVariable)
print(VariableName)
print(_my_variable)
print(_)

Output

3

4

5

AnalyticalNikita.io
  1. Most importantly, Identifiers cannot be keywords and can be of any length.

Type Conversions

Changing an object’s data type is known as type conversion. There are two types of Type Conversion in Python: 

  • Python Implicit Type Conversion
  • Python Explicit Type Conversion

Too heavy? Let’s break them out:

Python interpreter is smart enough to perform Implicit Type Conversion, reducing data loss automatically.

# Implicit Type Conversion
print(9+2.8)
print(type(9), type(2.8))
print(int(5.9))
print(float(3))
print(str('3'))
print(bool(0))

Output

11.8

<class 'int'> <class 'float'>

5

3.0

3

False

However, it also allows its user to easily convert objects’ datatypes using specified functions in Explicit Type Conversion, sometimes referred to as type-casting.

Note: You need to be super-cautious while type-casting, as it may lead to data loss if the object is forced to conform to another particular datatype.

# Explicit Type Conversion
print(9 + float('2.8'))
print(type(9), type(2.8))

Output

11.8

<class ‘int’> <class ‘float’>

But does that trigger permanent changes?

The Python Type Conversion operation doesn’t change the original data. However, it creates a new value for the operations.

Immutability in Python

You may have often heard that some Python data types are immutable.

  • Immutable objects: int, float, complex, str, tuple, frozenset.
  • Mutable objects: list, dict, set, bytearray.

But what does it mean?

Immutability means that its original state cannot be modified once an object is created. 

Memory-Level Understanding

Whenever we talk about immutability at the memory level, we mean that an immutable object cannot be altered directly. 

Any operation that seems to change to these objects actually creates a different memory allocation for these new objects with modified value/s.

Wherein the mutable objects share the same memory allocated previously. Changes to these objects occur in-place, modifying the original memory content without any new allocation.

Primitive datatypes are “Immutable”

id(): Returns the unique memory address for the unique objects.

# Printing addresses to verify immutability of primitive datatypes 
primitive_data1 = 10
primitive_data2 = primitive_data1
primitive_data2 = 1 # replaced data2

print("Address of data1 is: ", id(primitive_data1)) # different addresses
print("Address of data1 is: ", id(primitive_data2)) # different addresses
print("Data 1 now is: ", primitive_data1)

Output

Address of data1 is: 2615765789264

Address of data1 is: 2615765788976

Data 1 now is: 10

Deletion of Objects and Memory Management

Python’s memory management relies on two principles to handle the deletion of objects.

  1. Reference Counting:
    • Each object has a reference count (which can be found using the .getrefcount() function) that tracks the number of references pointing to it.
    • When the reference count drops to zero, the system deallocates the memory occupied by the object and makes it available for other uses.
  2. Cyclic References Counting:
    • Python also provides us with a garbage collector that handles the cyclic references. Sometimes, objects reference each other in a loop.
    • For instance, object A references object B, and object B references object A. Even if no other part of the program needs these objects, their reference counts never drop to zero because they reference to each other. This is where the garbage collector steps in.
    • Through the garbage collection process, Python automatically finds and frees up memory that is no longer being used by the program, especially for objects that reference each other in a cycle.

Tips and Tricks for Efficient Coding

Assign Multiple Variables on One Line

print(): Prints specific messages on the standard output device’s screen.

a, b = 12, 30 

# Rather 
# a = 12
# b = 30

print("Value of 'a' is" , a ,"and Value of 'a' is" , b)

Output

Value of 'a' is 12 and Value of 'a' is 30

Raise a number to a Power

pow(): Returns the value of x to the power y.  

power = pow(3, 5)
print("Power of 3 raise to 5: ", power)

Output

Power of 3 raise to 5: 243

Banker’s Rounding – Half towards Even

print("Round of 10.5 is" , round(10.5)) # round down to 10
print("Round of 11.5 is" , round(11.5)) # round up to 12

Output

Round of 10.5 is 10

Round of 11.5 is 12

Using “Underscores” in Large Numbers

billion = 1_000_000_000
print("Billion :", billion)

Output

Billion : 1000000000

Check if exists

del: Deletes the object.

# Set the variable 'age' to the value 16
age = 16
print("Initial value of 'age':", age)

# Check if 'age' is in the local and global namespaces
print("'age' in locals():", 'age' in locals())
print("'age' in globals():", 'age' in globals())

# Delete the variable 'age'
del age
# print("After deleting 'age':", age)  # This will raise an error since 'age' is deleted

# Check again if 'age' is in the local and global namespaces
print("'age' in locals():", 'age' in locals())
print("'age' in globals():", 'age' in globals())

print("\n")
# Set the variable 'age' to the value None
age = None
print("After setting 'age' to None:", age)

# Check again if 'age' is in the local and global namespaces
print("'age' in locals():", 'age' in locals())
print("'age' in globals():", 'age' in globals())

Output

Initial value of 'age': 16

'age' in locals(): True

'age' in globals(): True

'age' in locals(): False

'age' in globals(): False

After setting 'age' to None: None

'age' in locals(): True

'age' in globals(): True

Unpacking operator

# Function to prints character position
def position(x, y, z):
    print(f'Character to {x} {y} {z}')
  
# Unpack the list to its equivalent position  
pos = [5, 10, 15]
position(*pos) 

Output

Character to 5 10 15

Using “all” operator instead of “and”

all(): Returns “True” if all elements in an iterable are “True”.

and(): Returns “True” if both operands are “True”.

# Define age and reputation
age = 21
reputation = 20

# Create a list of conditions
conditions = [ 
    age >= 21, # Check if age is greater than or equal to 21
    reputation > 25 # Check if reputation is greater than 25
]

# Use all() to allow access    
if all(conditions):
    print("You're an admin. Allowed the access.")
else:
    print("You're a standard user. Not allowed the access.")

Output

You're a standard user. Not allowed the access.

Using “any” operator instead of “or”

any(): Returns “True” if at least one element in an iterable is “True”.

or(): Returns “True” if at least one operand is “True”.

# Define age and reputation
age = 21
reputation = 20

# Create a list of conditions
conditions = [ 
    age >= 21, # Check if age is greater than or equal to 21
    reputation > 25 # Check if reputation is greater than 25
]

# Use any() to allow access    
if any(conditions):
    print("You're an admin. Allowed the access.")
else:
    print("You're a standard user. Not allowed the access.")

Output

You're an admin. Allowed the access.

Working with String

In Python, specifically, strings are a sequence of Unicode Characters:

Why Unicode Characters?

To encounter this problem, firstly, we need to understand a brief about ASCII (American Standard Code for Information Interchange) and Unicode Values: 

ASCII vs. Unicode

  1. ASCII
    1. Character Set Limitation: Since ASCII can only represent 128 characters (in its 8-bit form), which only includes English letters, digits, punctuation marks, and control characters.
    2. Language Limitation: ASCII is also limited to the English language. This makes it incompatible with Machine Translations and Language Models due to its inability to represent characters from other languages.
  2. Unicode
    1. Extensive Character and Symbol Set: It can represent over 143,000 characters from different languages and symbol sets, including special characters, emojis, and much more.
    2. Most Language Coverage: Unicode is more versatile because it supports most of the characters from the world’s writing systems.
    3. Multiple Encodings: It also offers different encodings, such as UTF-8, UTF-16, and UTF-32, which can efficiently store characters.

I believe it is now clearer to you that Python strings use Unicode values rather than ASCII. This gives Python a much wider array of characters to represent different languages and a variety of emoji symbols.

String is a universal data type; any data type can be type-cast as “string” or “object.”

Before digging into codes, let’s discuss the most important concept that is helpful for both interview preparation and day-to-day work as a DS.

String and Memory Management

As we already know, strings in Python are immutable, and their deletion follows the general rule of immutable objects.

  • Single Reference: Deleting a string object with only one reference immediately deallocates its memory for future use.
  • Multiple References: If a string object has multiple references, deleting one reference will not immediately deallocate the memory. The memory will be freed up when the last reference is deleted.

Printing Colored Text

# Print statements with colored text using ANSI escape codes
print(f"\033[97mCoding is \033[92mexciting")
print(f"\033[97mCoding is \033[92mcreative")
print(f"\033[97mCoding is \033[91mchallenging")
print(f"\033[97mCoding is \033[91mstressful")
print("\n")
print(f"\033[93mCoding Everyday!")

The output of this code is really colorful. So, check out this link.

Open a Web Browser

# Open a web browser and navigate to Google
import webbrowser

webbrowser.open('https://www.google.com')

Output

True

Concatenation without “+” Operator

# Concatenate strings without using "+" sign
message = "Hello, this " "string concatenation" " without using '+' sign."
print(message)

Output

Hello, this string concatenation without using '+' sign.

“split” Function of string object

split(): Splits the string into a list using a specific delimiter.

# Split a fullname into first and last names based on underscore separator
full_name = "Analytical_Nikita.io"
first_name , last_name = full_name.split(sep= "_")
print(first_name, last_name)

Output

Analytical Nikita.io

“join” Function of string object

join: Joins the list into a single string with a specified separator.

# Join a list of names into single string with an underscore separator
names = ["Analytical", "Nikita.io"]
full_name = "_".join(names)
print(full_name)

Output

Analytical_Nikita.io

Working with “in” Substring

in: Returns the index of the first occurrence in a specific string. 

# Check if the substring is present in string and print its index
if "Analytical" in "AnalyticalNikita.io":
    print("The substring is present at", "AnalyticalNikita.io".index("Analytical"), "index.")

Output

The substring is present at 0 index.

Note: If the value is not present in the substring it will throw an error, to avoid this, we use find() function.

Get index using find() method

find(): Returns the index of first occurrence in a specific string. If not found, return -1.

# Finding a substring in a string
print("The substring is present at", "AnalyticalNikita.io".find("Analytics"), "index.")

Output

The substring is present at -1 index.

Using “id” to get the identity of the data

id(): Returns the unique memory address for the unique objects.

# Printing address of specific data
data = {"AnalyticalNikita.io": 1}
print("Address of this data is: ", id(data))

Output

Address of this data is: 2615849709376

Aliases

We use an alias if we want two variables to point to the same data or if we want functions to be able to modify arguments passed to them.

# Aliasing 
data1 =  {"AnalyticalNikita.io": 1}
data2 = data1
data2['DataAnalytics'] = 9

# Print memory address of both dictionaries 
print("Address of data1 is: ",id(data1))
print("Address of data2 is: ",id(data2))

# Print the modified dictionary
print("Data1 now is: ", data1)

Output

Address of data1 is: 2615850448448

Address of data2 is: 2615850448448

Data1 now is: {'AnalyticalNikita.io': 1, 'DataAnalytics': 9}

Using print end = ” ” to change ending

# List of favorite technologies
favorite_technologies = ["Python", "SQL", "Power BI", "Tableau", "SAS", "Alteryx"]

# Iterate over the list of favorite technologies
for technology in (favorite_technologies):
    print(technology, end = " ")
    
print("") #to go to next line for the next output

Output

Python SQL Power BI Tableau SAS Alteryx

Print multiple elements with commas

# Define name and list of favorite technologies
name = "AnalyticalNikita.io"
favorite_technologies = ["Python", "SQL", "Power BI", "Tableau", "SAS", "Alteryx"]

print(name, "is proficient in", favorite_technologies)

Output

AnalyticalNikita.io is proficient in ['Python', 'SQL', 'Power BI', 'Tableau', 'SAS', 'Alteryx']

String formatting using “f-string”

f” “: Embed expressions inside the string literals.

# Implict string conversion
name = "AnalyticalNikita.io"

print(f"My name is {name}.") 

Output

My name is AnalyticalNikita.io.

Returning multiple values and Assigning to multiple variables

# Function to return a tuple of positions
def returning_position():
    # In, real scenario, these values are obtained from user or database
    return 5, 10, 15, 20

print("A tuple", returning_position()) 

# Assign the values from tuple to multiple variable
x, y, z, a = returning_position()
print("Assigning to multiple variables: ", "x is", x, "y is", y,"z is", z,"a is", a)

Output

A tuple (5, 10, 15, 20)
Assigning to multiple variables: x is 5 y is 10 z is 15 a is 20

Ternary conditional operator or string comprehension

# Method 1: If - else
reputation = 30
if reputation > 25:
    name = "admin"
else:
    name = "visitor"
print(name)

# Method 2: String comprehension
reputation = 20
name = "admin" if reputation > 25 else "visitor"
print(name)

Output

admin

visitor

Flag variable

Break: Terminates the current loop.

# Create a list of fruits 
fruits = ['apple', 'banana', 'orange', 'grape', 'kiwi', 'apple']

# Option 1: Check if 'orange' is in the list directly
if 'orange' in fruits: print("Yes, 'orange' is in the list.")

# Option 2: Use a flag variable to check for 'kiwi'
kiwi_found = False # Assume
for fruit in fruits:
    print(fruit, end=" ") # do something with each element if needed
    if fruit == 'kiwi':
        kiwi_found = True # could count elements
        break

if kiwi_found: print("\nYes, 'kiwi' is in the list.")

# Option 3: Check if 'grapefruit' is in the list without using break
for fruit in fruits:
    print(fruit, end=" ")
    if fruit == 'grapefruit':
        break
else: #no break
    print("\nNo 'grapefruit' found in the list.")

Output

Yes, 'orange' is in the list.

apple banana orange grape kiwi

Yes, 'kiwi' is in the list.

apple banana orange grape kiwi apple

No 'grapefruit' found in the list.

Remove list duplicates using a set

# Create a list of fruits with duplicate data
fruits = ['apple', 'banana', 'banana', 'banana', 'kiwi', 'apple']

# Removing duplicate items of list using set 
unique_fruits = list(set(fruits))
print("Unique fruits are: ", unique_fruits)

Output

Unique fruits are: ['apple', 'kiwi', 'banana']

Using “in” method instead of complex conditional

It is popularly used while checking against a list of values.

# Check the weather condition and cancel the plan if the weather in the given list
weather = "rainy"

if weather in ['rainy', 'cold', 'snowy']:
    print("Plan is cancelled")

Output

Plan is cancelled

Bugs and Debugging

It may be frustrating, but mistakes are truly inevitable when writing a program. Those programming errors are called bugs, and the process of fixing them is called debugging.

Broadly, three types of common errors can occur in a program:

  1. Syntax Error: The rules of identifiers, the rules about a program’s structure, were already discussed above. Python immediately throws up an error if it finds a syntax error.
# Invalid Identifier
name! = "analyticalnikita.io"

Output

Cell In[1], line 1
name! = "analyticalnikita.io"
          ^
SyntaxError: invalid syntax
  1. Runtime / Exception Error: Your program may start running if there’s no syntax error. But if something goes wrong, an error message will be displayed on your screen, and the program will stop running.
# TypeError is a type of Exception 

# Input string
inputString = "analyticalnikita.io"
# Input Number
inputNumber = 29
# Adding both integer and string values
print(inputString + inputNumber)

Output

TypeError: must be str, not int
  1. Semantic Error: Identifying these types of errors is tricky because they run without generating an error message but don’t accomplish their intended purpose.
# Finding average of 100 and 300
100 + 300 / 2

Output

250

For some programmers, programming is debugging a program until it does what you want. 

But if you spend a lot of time debugging your code, that’s a sign that you are writing too much code before testing it.

The idea here is to take smaller steps and divide your code into modular components. This will help you write better code and make debugging it much easier.

Conclusion

In this article, I have provided you with a comprehensive overview of the simplicity of the Python programming language. We’ll later discuss the versatility of awesome frameworks that make it a powerful tool for AI and ML. 

It is the most popular programming language in the data science field due to its easy-to-learn syntax, extensive libraries, and strong community support.

Understanding Python programming fundamentals, such as static vs. dynamic typing, memory management, and useful string operations, can significantly improve your coding skills.

Remember, practice and constant learning are the keys to becoming a pro in any programming language. You can write better production-level code by following these practical tips and suggestions.

If you are looking to master a coding language online, then power up your career with the best and most popular data science language, Python. Leverage your Python skills to start your Data Science journey. This course is intended for beginners with no coding or Data Science background.

Frequently Asked Questions

Q1. What is the difference between static and dynamic typing?

Ans. Static typing determines the methods to be invoked during compilation, while dynamic typing determines the datatype of variables at runtime.

Q2. What are the key principles of Python’s memory management?

Ans. Python manages memory using:
A. Reference Counting: It helps to track the number of references pointing to an object. Memory is freed when the count drops to zero.
B. Cyclic Reference Counting: The garbage collector handles the cyclic references to deallocate the memory that is no longer being used.

Q3. How do you improve Python programming skills?

Ans. To write better Python code:
A. Thoroughly understand the basic concepts of Python.
B. Write modular code for your team and test often to catch bugs early.
C. Practice reading and writing production-level codes.

Q4. What is Fundamentals of Python Programming

Ans. “Fundamentals of Python Programming” covers essential concepts like syntax, variables, data types, control structures (if, loops), and setting up the Python environment for coding.

Nikita Prasad 17 Jul, 2024

Hi-ya!!! 👋 I'm Nikita Prasad Data Analyst | Machine Learning and Data Science Practitioner ↪️ Checkout my Projects- GitHub: https://github.com/nikitaprasad21 Know thy Author: 👩🏻‍💻 As an analyst I am eager to gain a deeper understanding of the data lifecycle with a range of tools and techniques, distilling down data for actionable takeaways using Data Analytics, ETL, Machine Learning, NLP, Sentence Transformers, Time-series Forecasting and Attention to Details to make recommendations across different business groups. Happy Learning! 🚀🌟

Frequently Asked Questions

Lorem ipsum dolor sit amet, consectetur adipiscing elit,

Responses From Readers

Clear