IIDT – Blackbucks Short Term Internships AIML Session
04 _ APSCHE
If Statements
Definition: An if statement is a control flow statement that allows code to be executed only if
a specified condition is true.
Syntax:
if condition:
# Code to execute if the condition is true
Condition: An expression that evaluates to either true or false.
Ex:
age = 18
if age >= 18:
print("You are an adult.")
Else Statement: Provides an alternative block of code to execute if the condition is false.
if condition:
# Code to execute if the condition is true
else:
# Code to execute if the condition is false
Ex:
age = 16
if age >= 18:
print("You are an adult.")
else:
print("You are not an adult.")
Explanation:
condition: This is any expression that evaluates to True or False. It can involve
comparisons (like x > 5), checking variable values, or any logic that results in a
boolean outcome.
Indentation: Notice the indentation after the if statement. This is crucial in Python as
it defines the code block that belongs to the if statement. Only indented lines are
considered part of the code to be executed if the condition is True.
Execution:
If the condition evaluates to True, the indented code block gets executed.
If the condition is False, the indented code block is skipped, and the program continues
to the next line after the if statement.
Example:
Python
age = 25
if age >= 18:
print("You are eligible to vote.")
In this example, if age (which is 25) is greater than or equal to 18, the message "You are
eligible to vote" will be printed. If age is less than 18, the message won't be printed.
Nested if:
Elif Statement: Short for "else if," used to check multiple conditions.
if condition1:
# Code to execute if condition1 is true
elif condition2:
# Code to execute if condition2 is true
else:
# Code to execute if none of the conditions are true
Ex:
age = 20
if age < 13:
print("You are a child.")
elif age < 18:
print("You are a teenager.")
else:
print("You are an adult.")
Logical Operators:
Logical operators are used to combine multiple conditions. The common logical operators
are:
1. AND (and, &&): Returns true if both conditions are true.
2. OR (or, ||): Returns true if at least one condition is true.
3. NOT (not, !): Returns true if the condition is false.
Ex:
age = 17
has_permission = False
if age >= 18 or (age >= 16 and has_permission):
print("You can drive.")
else:
print("You cannot drive.")
Truthy Values:
These are values that get evaluated as True when used in a boolean context.
They include:
o Non-zero numbers (e.g., 1, -5.2)
o Non-empty strings (e.g., "Hello", " ")
o Non-empty sequences (e.g., lists like [1, 2, 3], tuples like (1, "apple"), dictionaries
like {"name": "Alice"}, sets like {1, 2})
o Most custom objects (their behavior might depend on how the __bool__ method
is implemented)
Falsy Values:
These are values that get evaluated as False when used in a boolean context.
They include:
o The literal value False
o The literal value None (represents the absence of a value)
o The number 0 (of any numeric type, like 0, 0.0, 0j)
o Empty sequences (e.g., empty list [], empty tuple (), empty dictionary {},
empty set set())
Things to remember:
Truthy and falsy are not the same as True and False. They define how a value behaves
in a boolean context, not its absolute truth value.
You can use the built-in bool() function to explicitly convert any value to its boolean
equivalent (True or False).
Short-circuiting: in Python refers to the behavior of certain logical operators (and and or)
where evaluation stops as soon as the truth value of the expression is determined.
Here's a breakdown for and and or:
and Operator:
Evaluates from left to right.
If the first operand is False (falsy value), the expression is automatically False and
the second operand is not even evaluated.
This is because any value paired with False using and will always result in False.
If the first operand is True (truthy value), then the second operand is evaluated, and
the entire expression's truth value depends on both operands.
Example:
Python
x = 5
name = ""
if x > 0 and name: # Name is empty string (falsy)
print("Valid combination") # Not executed
or Operator:
Evaluates from left to right.
If the first operand is True (truthy value), the expression is automatically True and
the second operand is not evaluated.
This is because any value paired with True using or will always result in True.
If the first operand is False (falsy value), then the second operand is evaluated, and
the entire expression's truth value depends on both operands (if the second operand is
truthy, the expression becomes True).
Example:
Python
age = 17
has_permission = True
if age >= 18 or has_permission: # has_permission is True (truthy)
print("Access granted") # Executed
Benefits of Short-circuiting:
Improves code efficiency by potentially avoiding unnecessary evaluations, especially
when dealing with functions that might have side effects.
Can be used for concise conditional logic.
Remember:
Short-circuiting only applies to and and or operators.
Be cautious when using short-circuiting with functions that might have side effects, as
those side effects might still occur even if the function itself isn't fully evaluated.
Comparison operators in Python are used to compare the values of two operands and return a
boolean value (True or False) based on the comparison. They are fundamental for making
conditional decisions in your code.
Here's a quick rundown:
Operators:
==: Equal to (checks if values are equal)
!=: Not equal to (checks if values are different)
<: Less than (checks if left operand is less than right operand)
>: Greater than (checks if left operand is greater than right operand)
<=: Less than or equal to
>=: Greater than or equal to
Examples:
x = 10
y=5
# Equality
if x == y:
print("x and y are equal") # Not executed
# Inequality
if x != y:
print("x and y are not equal") # Executed
# Less than and Greater than
if x < y:
print("x is less than y") # Not executed
if x > y:
print("x is greater than y") # Executed
# Less than or equal to and Greater than or equal to
if x <= y:
print("x is less than or equal to y") # Not executed
if x >= y:
print("x is greater than or equal to y") # Executed
Memory Allocation:
In Python, memory allocation is automatic, handled by the CPython implementation's
memory manager.
When you create objects (like lists), the interpreter allocates memory from a private
heap to store the object's data.
Each object also has a unique memory address that identifies its location in memory.
Empty Lists and Memory Addresses:
Even though two empty lists might seem like the same thing, they actually reside in
different parts of the memory.
When you create separate empty lists using [], Python allocates distinct memory
blocks for each list, resulting in unique memory addresses.
Comparison by Identity vs. Value:
The == operator in Python compares object identity by default, not value.
This means it checks if both objects refer to the same memory location.
Since two empty lists are in different memory locations, they are considered non-
equal by the == operator.
Why Sund was Correct:
Sund correctly recognized that the == operator was comparing memory addresses, not
the contents (which are both empty in this case).
Because the empty lists have different memory addresses, they are considered
unequal.
Alternative for Value Comparison:
If you want to compare if two lists have the same elements (regardless of memory
address), you can use the is operator to check for object identity (sameness) or list
comprehension with a set to compare element values.
While Loops: A while loop in Python is a control flow statement that allows you to execute a
block of code repeatedly as long as a certain condition remains True.
1. Initialization: The condition is evaluated before the first iteration.
2. Loop Continuation:
o If the condition is True:
The code block within the loop body is executed.
The condition is evaluated again.
o If the condition becomes False:
The loop terminates.
3. Iterations: Steps 2.a and 2.b are repeated until the condition becomes False.
Example:
count = 0
while count < 5:
print("Count:", count)
count += 1 # Increment count by 1 in each iteration
• For Loops: A control flow statement for iterating over elements in a sequence.
• Structure: for item in iterable: # Code to be executed.
• item: Variable name representing each item during iteration (can be named anything).
• iterable: The object containing the sequence to iterate over (must be iterable).
• Iterables: Objects that can be used in a for loop, providing a way to access elements one by
one.
• Examples: Lists, tuples, strings, sets, dictionaries (and custom objects with __iter__).
• Loop Process: 1. Get iterator, 2. Enter loop, 3. Assign item, 4. Execute code, 5. Advance
iterator, 6. Repeat until done.
• Benefits: Avoids explicit indexing and loop counters, improves readability.
• Flexibility: Iterates over various iterables, not limited to a specific type.
Ex:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(f"I like {fruit}.")
Enumerate:
The enumerate function in Python adds a counter (index) to each item in an iterable (like a
list) and returns an object for looping. This object lets you access both the index and the value
of each item in a single loop.
Purpose: Track index and value while looping through iterables.
Returns: Object yielding tuples of (index, value).
Use Case: When you need both index and value in your loop.
Example: for index, fruit in enumerate(fruits): print(index, fruit).
iterating over a dictionary:
• Iterating over dictionaries in Python directly gives you the keys.
• Keys are not guaranteed to be in insertion order.
• To access values, use the key within the loop:
Ex:
for key in my_dict:
print(my_dict[key]) # Access value using key
• For key-value pairs together, use the items() method:
for key, value in my_dict.items():
print(f"{key}: {value}")
Range Function:
Creates a sequence of numbers within a specified range (inclusive start, exclusive
end).
Demonstrates using single argument (default start of 0) and explicit range.
Discusses behavior of out-of-range indexing and backward loops.
Control Flow Statements:
Explains break for exiting loops and else for code after while loop finishes.
Highlights break's usefulness in specific situations (infinite loops, desired responses).
Ex:
for number in range(1, 11): # Loop through numbers 1 to 10
if number == 5:
print("Found the number 5!")
break # Exit the loop after finding 5
else:
print(number)
Input and Control Flow:
Discusses input handling and line-by-line execution in Python.
Introduces pass (does nothing but syntactically valid) and continue (skips current
iteration).
Functions:
Emphasizes functions for code reusability (def keyword for definition, call to
execute).
DRY (Don't Repeat Yourself) principle and avoiding code repetition.
Clarifies function invocation using name and embedding code for reuse.
Explains arguments (passed values during function call).
Touches on type safety and optional type annotations in Python.
Dynamic Typing:
Discusses Python's dynamic typing (types inferred at runtime).
Warns against excessive flexibility leading to bad practices.
Introduces default parameter patterns in Python functions.
x = 10 # Assign an integer value to x
print(type(x)) # This will print "<class 'int'>"
x = "Hello, world!" # Reassign a string value to x
print(type(x)) # This will print "<class 'str'>"