Intermediate Python Mastery
Python Core Concepts
Beyond the Basics
If you've programmed in another language, Python's syntax might feel both familiar and strange. The biggest difference is often the first one you notice: indentation isn't just for style, it's syntax. In Python, the whitespace at the beginning of a line defines code blocks. Where you might use curly braces {} in C++ or Java, Python uses a colon : followed by an indented block of code.
This design choice, called the [{
}], forces code to be written in a clean, readable style. It eliminates arguments over brace placement and makes the visual structure of the code directly represent its logical structure.
# In Python, indentation defines the scope
def check_temperature(temp):
if temp > 30:
print("It's hot outside!")
else:
print("It's a pleasant day.")
check_temperature(35)
This rule, created by Python's inventor , is a core part of the language's philosophy. It emphasizes code readability, a principle so important it's enshrined in the Zen of Python: "Readability counts."
Variables as Labels
In many languages, a variable is like a box that holds a value. In Python, it's more like a label or a name tag that points to an object in memory. This distinction is crucial when dealing with mutable and immutable data types.
Immutable types, like integers, strings, and tuples, cannot be changed after they are created. When you perform an operation that seems to modify one, Python actually creates a new object and points the variable label to it.
# x is a label for the integer object 5
x = 5
print(id(x)) # Prints the memory address of 5
# This doesn't change the 5. It creates a new object, 6,
# and moves the label 'x' to point to it.
x = x + 1
print(id(x)) # Prints the memory address of 6 (a different address)
Mutable types, like lists and dictionaries, can be changed in place. If you have two variables pointing to the same list, modifying the list through one variable will affect the other, because they both point to the exact same object.
This is also related to Python's use of . You don't declare a variable's type. Instead, the type is determined at runtime based on the object the variable's name is pointing to. You can reassign the same variable name to point to an object of a completely different type without any issue.
Smarter Control Flow
Python's loops have an optional else block that you won't find in many other languages. This block executes only if the loop completes its entire sequence without being terminated by a break statement.
It’s useful for search operations. You can loop through a list to find an item. If you find it, you break. The else block then serves as a clean way to handle the case where the item was not found, without needing a separate flag variable.
# Using for-else to find a prime number
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(f"{n} equals {x} * {n//x}")
break
else:
# Loop fell through without finding a factor
print(f"{n} is a prime number")
The same logic applies to while-else loops. The else block runs if the while condition becomes false, but not if the loop is exited via break.
Flexible Functions
Python functions offer a very flexible way to handle arguments. Beyond standard positional arguments, you can use keyword arguments to pass values by name, which makes function calls more explicit and readable.
def create_user(username, age, status="active"):
print(f"User: {username}, Age: {age}, Status: {status}")
# Using keyword arguments makes the call's intent clear
create_user(status="pending", username="alex", age=30)
You can also define functions that accept an arbitrary number of arguments. A parameter prefixed with a single asterisk (*args) collects any extra positional arguments into a tuple. A parameter with a double asterisk (**kwargs) collects extra keyword arguments into a dictionary.
| Parameter | How it Works | Example |
|---|---|---|
*args | Collects extra positional arguments into a tuple. | def f(a, *args): |
**kwargs | Collects extra keyword arguments into a dictionary. | def f(a, **kwargs): |
For small, single-expression functions, Python provides lambda functions. These are anonymous functions defined on the fly, often used as arguments to higher-order functions like map() or sorted().
points = [(1, 2), (3, 1), (5, 4), (2, 0)]
# Sort the points based on their second value (the y-coordinate)
# The lambda function defines the sorting key inline.
points.sort(key=lambda point: point[1])
print(points)
# Output: [(2, 0), (3, 1), (1, 2), (5, 4)]
Now, let's test your understanding of these core concepts.
In Python, what is used to define a block of code, such as the body of a loop or function?
Consider the following Python code:
list_a = [1, 2, 3]
list_b = list_a
list_b.append(4)
print(list_a)
What will be the output?
With these Python-specific ideas refreshed, you are ready to tackle more complex topics.