Advanced Python Fundamentals
These features are part of modern Python and are widely used in professional applications and popular frameworks such as FastAPI, Flask, Django, NumPy, Pandas, and many other third-party libraries.Topics Covered
In this module, you’ll learn:- Everything is an Object & Variables as References
- Integer Value Caching (Integer Interning)
- Mutability (Mutable vs Immutable Objects)
- Floating Point Precision Nuances (
0.1 + 0.2 != 0.3) - Advanced String Indexing and Slicing
- Important String Operations (split, join, strip, replace)
- Python Nuances
for-elseandwhile-else- Function Arguments
- Packing and Unpacking
Practice Along: 💻 VS Code | 🚀 Colab | 📥 Download
Verify Solutions: 💻 VS Code | 🚀 Colab | 📥 Download
Everything is an Object & Variables as References
In Python, everything is treated as an object—including integers, floats, strings, functions, and modules. Furthermore, variables in Python do not hold values directly. Instead, variables hold references (pointers) to the location in memory where the object is stored.Understanding Object Identity
You can use the built-inid() function to find the memory address of an object. The is operator checks if two references point to the exact same object in memory, while == checks if their actual values are equal.
Show Output
Show Output
Show Output
Show Output
Verification: Integers and Floats are Objects
Unlike languages like C++ or Java where primitive types (such asint, double) store raw values directly in variables, in Python, even integers and floats are objects.
This has two major implications:
- Variables assigned to integers or floats store references (pointers) to those numeric objects in memory.
- Integers and floats have their own built-in properties and methods that you can invoke using dot notation.
1. Verifying Reference Behavior with Float Objects
When you create two floats independently, Python creates two distinct objects in memory. The variablesf1 and f2 store references to these distinct objects:
Show Output
Show Output
2. Accessing Methods on Numbers
Since numbers are objects, they have built-in methods.[!NOTE] If you call a method directly on a literal number, you must enclose the number in parentheses (e.g.,(10).bit_length()). Otherwise, Python’s parser will confuse the dot.with a decimal point.
Built-in Methods on Integers:
bit_length(): Returns the number of bits required to represent an integer in binary.as_integer_ratio(): Returns a tuple of(numerator, denominator)representing the integer as a fraction.
Show Output
Show Output
Built-in Methods on Floats:
is_integer(): ReturnsTrueif the float has no fractional part (e.g.,10.0).as_integer_ratio(): Returns the exact fraction representing the float.
Show Output
Show Output
Exercise 1
Assign the string"FastAPI" to a variable a, and then assign a to b. Verify if they point to the same object using is and by printing their ids.
Solution
Solution
Exercise 2
Create two float variables with the value2.5 independently. Compare them using == and is, and explain the result.
Solution
Solution
Integer Value Caching (Integer Interning)
In Python, memory optimization is built into the interpreter. One of the most famous optimizations is Integer Value Caching (also known as integer interning). At startup, Python (specifically the standard CPython implementation) pre-allocates and caches all integers in the range[-5, 256].
When you reference any integer in this range, Python does not create a new object. Instead, it returns a reference to the existing cached integer object.
Show Output
Show Output
Show Output
Show Output
Exercise 1
Predict the output of the following comparisons:Solution
Solution
256 lies within the cache range [-5, 256], so a and b refer to the same object. -6 is outside the cache range, so x and y refer to different objects.Exercise 2
Write a code snippet to verify that floats are not cached in the same manner as small integers (e.g., compare1.0 and 1.0 using is).
Solution
Solution
Mutability (Mutable vs Immutable Objects)
In Python, every object is classified as either mutable or immutable. Understanding this distinction is crucial for understanding how Python handles variable assignment, function arguments, and memory.Immutable Objects
An immutable object’s state cannot be changed after it is created. Examples of immutable types in Python:- Numeric types (
int,float,complex) - Strings (
str) - Tuples (
tuple) - Booleans (
bool) - Frozensets (
frozenset)
Show Output
Show Output
Mutable Objects
A mutable object’s state can be changed in-place after it is created. Examples of mutable types in Python:- Lists (
list) - Dictionaries (
dict) - Sets (
set)
id).
Show Output
Show Output
A Common Nuance: Mutable Objects Inside Immutable Containers
If a tuple contains a mutable object, such as a list, the tuple itself is still immutable (its references cannot change), but the list inside it can be mutated.Show Output
Show Output
Exercise 1
Predict whether the following operation is valid and what it outputs:Solution
Solution
Exercise 2
What is the final content oflist_b?
Solution
Solution
list_b = list_a) copies the reference, both variables point to the same list object in memory.Floating Point Precision Nuances
Floating-point numbers in computers are represented as binary fractions. This leads to some surprising behavior when performing decimal calculations.The Classic Floating-Point Issue: 0.1 + 0.2
In Python:
Show Output
Show Output
Why Does This Happen?
Numbers like0.1 and 0.2 have infinite repeating representations in binary (similar to how is in base 10). The computer must truncate these values, introducing a microscopic rounding error. When you add them, the errors combine, resulting in 0.30000000000000004.
Why Does 0.5 + 0.25 == 0.75 Work?
Unlike 0.1 and 0.2, the fractions 0.5 (), 0.25 (), and 0.75 () are sums of exact powers of 2. They can be represented perfectly in binary.
Show Output
Show Output
How to Handle Exact Decimal Math
If your application requires exact decimal calculations (e.g., handling money or financial transactions), use Python’s built-indecimal module:
Show Output
Show Output
Decimal constructor. Passing floats like Decimal(0.1) preserves the float’s floating-point precision error).
Exercise 1
Predict the output of:Solution
Solution
Decimal(0.1) inherits the imprecise representation of the float 0.1, whereas Decimal('0.1') represents exactly 0.1.Exercise 2
Will the expression0.125 + 0.125 == 0.25 be True or False?
Solution
Solution
0.125 () and 0.25 () can be represented exactly in binary, so no rounding error occurs.String Indexing and Slicing
Strings are sequences of characters. Python allows extracting portions of a string using indexing and slicing.Understanding the Slice Components
- start – Starting index (inclusive)
- stop – Ending index (exclusive)
- step – Number of characters to skip
Basic Slicing
Show Output
Show Output
Extracting a Portion of a String
Show Output
Show Output
Omitting Start or Stop
Show Output
Show Output
Using Step
Show Output
Show Output
Reversing a String
A negative step traverses the string from right to left.Show Output
Show Output
Practical Example
Extract the file extension.Show Output
Show Output
Exercise 1
Extract"Python" from the following string.
Solution
Solution
Exercise 2
Reverse the following string using slicing.Solution
Solution
Important String Operations for Data Processing
In real-world data processing, indexing and slicing are rarely enough. We frequently need to clean, transform, partition, and format string data.1. Cleaning Whitespace with .strip()
Whitespace at the beginning or end of strings (like spaces, tabs, or newlines) is common in raw data imports.
.strip(): Removes leading and trailing whitespace..lstrip(): Removes leading whitespace only..rstrip(): Removes trailing whitespace only.
2. Splitting and Joining
Converting between single strings and lists of substrings is a core data-processing pattern.Splitting Strings (.split())
The .split(sep) method splits a string on a specified separator and returns a list of substrings. If no separator is specified, it splits on any consecutive whitespace.
Joining Lists (.join())
The .join(iterable) method is called on the separator string and merges a list of strings into a single string.
3. Replacing Substrings (.replace())
You can swap out characters or substrings using .replace(old, new).
4. Validating Prefix/Suffix (.startswith() and .endswith())
Useful for filtering filenames, URLs, or protocols.
Exercise 3
Clean a list of raw email strings by removing leading/trailing whitespaces and converting them to lowercase.Solution
Solution
Exercise 4
Given a raw CSV row"john doe, 28, Developer, New York", parse the columns, strip the whitespace, capitalize the name ("John Doe"), and join the columns back using a semicolon ; as the separator.
Solution
Solution
Python Nuances
Python provides several elegant language features that simplify common programming tasks.Short-Circuit Evaluation
Logical operators don’t always evaluate every expression.Using or
Suppose a user doesn’t enter a name.
Show Output
Show Output
Show Output
Show Output
Using and
Suppose a user must be logged in before displaying a welcome message.
logged_in is False, the second expression is never evaluated.
Exercise 1
Print"Anonymous" whenever name is an empty string.
Solution
Solution
Exercise 2
Print"Access Granted" only when is_admin is True.
Solution
Solution
One-line if only statement
If you want to run a single statement on a condition without an else, you can write it on one line (though this is a statement, not an expression that returns a value):
Exercise 1
Write a one-line conditional expression that assigns"Even" or "Odd" to a variable label based on whether num is divisible by 2.
Solution
Solution
Exercise 2
Write a one-line conditional expression to assign"Pass" to a variable result if score >= 50 else "Fail".
Solution
Solution
Conditional Expressions (One-line if-else / Ternary Operator)
A conditional expression (also known as a ternary operator) allows you to assign a value to a variable based on a condition in a single line.
Syntax
if-else blocks:
Show Output
Show Output
Chained Comparisons
Many range checks require two comparisons. Traditional approach:Exercise 1
Check whethertemperature lies between 20 and 35.
Solution
Solution
Exercise 2
Check whether a character is an uppercase alphabet.Solution
Solution
Multiple Assignment and Variable Swapping
Multiple Assignment
Instead of assigning each variable separately,Assigning Multiple Values
Swapping Variables
Traditional approach:Show Output
Show Output
Exercise 1
Assign"Unknown" to three variables using a single statement.
Solution
Solution
Exercise 2
Swap the values of two variables without using a temporary variable.Solution
Solution
for-else and while-else
Unlike many programming languages, Python allows an optional else block after loops.
The else block executes only when the loop completes normally without encountering a break statement.
Example 1: Searching for a Divisor
Suppose we want to check whether a number has any divisor other than1 and itself.
Show Output
Show Output
break, so the else block is skipped.
Example 2: Checking Whether a Number is Prime
A prime number has no divisors other than1 and itself.
Show Output
Show Output
for-else.
while-else
The else block also works with while loops.
Show Output
Show Output
Exercise 1
Write a program to check whether a given number is a perfect square usingfor-else.
Solution
Solution
Exercise 2
Print all prime numbers between50 and 100 using for-else.
Solution
Solution
Function Arguments
Functions become more flexible when they can accept arguments in different ways. Python supports positional arguments, keyword arguments, positional-only parameters, and keyword-only parameters.Positional Arguments
Positional arguments are matched with function parameters based on their position.Show Output
Show Output
"Alice"is assigned toname"Hyderabad"is assigned tocity
Show Output
Show Output
Exercise 1
Create a functiongreet() that accepts a person’s name and prints a welcome message.
Solution
Solution
Exercise 2
Create a function that accepts a student’s name and course, then displays both values.Solution
Solution
Keyword Arguments
Keyword arguments pass values using parameter names instead of their positions.Show Output
Show Output
Exercise 1
Call the following function using keyword arguments.Solution
Solution
Exercise 2
Create a function that accepts a product name and price. Call it using keyword arguments.Solution
Solution
Mixing Positional and Keyword Arguments
Positional and keyword arguments can be used together.Show Output
Show Output
Rule
All positional arguments must appear before keyword arguments. ✔️ CorrectSyntaxError because a positional argument appears after a keyword argument.
Exercise 1
Create a function that accepts a student’s name, course, and city. Pass the first argument positionally and the remaining arguments using keywords.Solution
Solution
Exercise 2
Create a function that accepts an employee’s name, designation, and salary. Mix positional and keyword arguments while calling it.Solution
Solution
Positional-only Parameters (/)
Python allows certain parameters to be passed only by position.
The / symbol separates positional-only parameters from the remaining parameters.
TypeError.
Why Use Positional-only Parameters?
Sometimes parameter names are implementation details and should not become part of the public interface. For example,Exercise 1
Create a functionmultiply() that accepts two positional-only parameters.
Solution
Solution
Exercise 2
Create a functiondiscount() that accepts price and discount percentage as positional-only parameters.
Solution
Solution
Keyword-only Parameters (*)
Parameters appearing after * must always be passed using keyword arguments.
TypeError.
Why Use Keyword-only Parameters?
Keyword arguments improve readability, especially when a function has several optional settings.Combining Both
A function can use positional-only and keyword-only parameters together.Exercise 1
Create a function where the first parameter is positional-only and the second parameter is keyword-only.Solution
Solution
Exercise 2
Create a function that calculates the area of a rectangle using keyword-only parameters.Solution
Solution
Packing and Unpacking
The operators* and ** have two complementary roles in Python.
- Packing collects multiple values into a single variable.
- Unpacking expands a collection into individual values.
Packing Positional Arguments (*args)
Sometimes we don’t know how many positional arguments a function will receive.
*args collects all remaining positional arguments into a tuple.
Show Output
Show Output
Show Output
Show Output
Exercise 1
Write a function that accepts any number of names and prints them.Solution
Solution
Exercise 2
Write a function that accepts any number of integers and returns the largest value.Solution
Solution
Packing Keyword Arguments (**kwargs)
**kwargs collects keyword arguments into a dictionary.
Show Output
Show Output
Show Output
Show Output
Exercise 1
Write a function that accepts any number of student details and prints them.Solution
Solution
Exercise 2
Write a function that prints all keyword arguments passed to it.Solution
Solution
Unpacking Positional Arguments (*)
Packing collects values.
Unpacking performs the opposite operation.
Instead of passing arguments one by one,
* operator expands the tuple into individual arguments.
Exercise 1
Call a function by unpacking a tuple.Solution
Solution
Exercise 2
Store two numbers in a tuple and unpack them while calling a function.Solution
Solution
Unpacking Keyword Arguments (**)
A dictionary can also be unpacked into keyword arguments.
Exercise 1
Create a dictionary containing product details and unpack it while calling a function.Solution
Solution
Exercise 2
Call a function by unpacking a dictionary containing employee details.Solution
Solution
Extended Unpacking
Python allows collecting the remaining values using*.
Show Output
Show Output
Exercise 1
Extract the first and last characters of the string"Developer".
Solution
Solution
Exercise 2
Extract the first character separately and store the remaining characters in another variable.Solution
Solution
Combining Everything
Python allows all parameter types to be used together.Show Output
Show Output
Exercise 1
Write a function that accepts a student’s name followed by any number of marks and prints the average.Solution
Solution
Exercise 2
Create a function that accepts a required username, any number of hobbies, and additional user details.Solution
Solution
Practice
To reinforce what you’ve learned in this section, practice with the interactive follow-along notebook:Follow-Along Practice
Summary
In this module, you learned several advanced Python features that make your code cleaner, more expressive, and more reusable.Key Concepts Covered
- Advanced string indexing and slicing
- Short-circuit evaluation using
andandor - Chained comparisons
- Multiple assignment and variable swapping
for-elseandwhile-else- Positional arguments
- Keyword arguments
- Mixing positional and keyword arguments
- Positional-only parameters (
/) - Keyword-only parameters (
*) - Packing positional arguments using
*args - Packing keyword arguments using
**kwargs - Unpacking tuples using
* - Unpacking dictionaries using
** - Extended unpacking
- Combining different parameter types in a single function