·10 min readprogramming

Python Crash Course: A Reviewer Note for the Impatient

#python#programming#hackerrank#crash-course

I Never Bothered to Study Python

I do not see the need to study it. It's pretty straightforward. You learn it as you code. And most importantly, I only do Python on hobby projects — when I write Jupyter notebooks to study trading strategies and do some analysis. It's not something I heavily use at work.

But here's the thing. You applied to a job. You need to master Python. You cannot use auto-complete aids or any AI tools. You are on your own. The environment feels like you're back in college. In my time as a student, our professor even told us to write code on yellow paper — and we were graded based on our fluency. Not in Python, but in Java. It's easy when you spend months doing lab exercises at school. But in this situation — the webcams are on, the screen share is on, and your every action is monitored.

Some say to just fuck it, just cheat. You can take that path. No one prevents you. But some people, like me, take up the challenge. I want to do it the old-fashioned way. AI dulled me these past few years during the AI revolution. I want to prove to myself that I am still capable of being sharp.

And you are on the right page.


HackerRank as the Training Ground

There's HackerRank, where you solve exercises in the programming language of your choice — including Python. As I write this blog, I am solving HackerRank problems. This blog post also serves as my note that I'd like to share publicly, hoping it would be helpful for you too.

But most importantly, this blog post is self-serving. If it doesn't work for you, it really does not matter. It's really for me. I'd be happy if this helps you. You're welcome.

A note on what I find useful here. The programming problems I solved on HackerRank that I felt worthy to post are below. But what's really useful to me are the syntax patterns — because I want to master Python syntax to the point where I can write the most elegant code under pressure. When I say elegant, I mean the simplest syntax. One-liner syntax that replaces what others write in ten lines. There's a certain pride in compressing a 10-line block into a single line.


The Cheat Sheet

from functools import reduce
from collections import Counter, defaultdict
from itertools import permutations, combinations
 
# --- print ---
print("Hello, World!")
 
# --- variables (dynamically typed) ---
x = 10          # int
y = 3.14        # float
s = "hello"     # str
b = True        # bool
 
# --- string formatting (f-strings are the way) ---
name = "Zero"
print(f"Hello, {name}")
print(f"{10 / 3:.2f}")  # 3.33
 
# --- multiple assignment ---
a, b, c = 1, 2, 3
a, b = b, a  # swap — no temp variable needed
 
# --- input ---
n = int(input())                        # single int
a, b = map(int, input().split())        # two ints on one line
nums = list(map(int, input().split()))  # list of ints
# input().split()                       -> ['12', '9', '61', '5', '14']
# map(int, ...)                         -> <map object> (lazy iterator)
# list(map(int, ...))                   -> [12, 9, 61, 5, 14]
# list comprehension equivalent:
[int(x) for x in input().split()]       # [12, 9, 61, 5, 14]
 
# --- lists ---
nums = [1, 2, 3, 4, 5]
nums.append(6)
nums.pop()       # removes last
nums[1:3]        # [2, 3] — slicing
nums[::-1]       # [5, 4, 3, 2, 1] — reverse
 
# --- list comprehension ---
squares = [x ** 2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]       # with condition
flat = [x for row in matrix for x in row]           # nested (flatten 2D)
 
# --- dict ---
d = {"a": 1, "b": 2}
d["c"] = 3
d.get("z", 0)   # returns 0 if key doesn't exist
squared = {x: x**2 for x in range(5)}               # dict comprehension
 
# --- sets ---
s = {1, 2, 3}
s.add(4)
s.discard(2)     # no error if missing
s & {2, 3, 4}    # intersection
s | {10}         # union
s - {1}          # difference
 
# --- tuples (immutable) ---
t = (1, 2, 3)
a, b, c = t  # unpacking
 
# --- ternary ---
x = "even" if n % 2 == 0 else "odd"
 
# --- loops ---
for i in range(5):         # 0 to 4
for i in range(1, 6):      # 1 to 5
for i in range(0, 10, 2):  # 0, 2, 4, 6, 8
for i, val in enumerate(nums):    # index + value
    print(i, val)
for a, b in zip(list1, list2):    # iterate two lists together
    print(a, b)
 
# --- functions ---
def add(a, b):
    return a + b
add = lambda a, b: a + b         # lambda — anonymous one-liner
def greet(name="World"):         # default args
    print(f"Hello, {name}")
def f(*args, **kwargs):           # variadic arguments
    print(args)                   # tuple
    print(kwargs)                 # dict
 
# --- strings (immutable — every operation returns a new string) ---
s = "hello world"
s.upper()                         # "HELLO WORLD"
s.split()                         # ["hello", "world"]
s.replace("world", "python")
s.startswith("hello")             # True
s.strip()                         # remove leading/trailing whitespace
"-".join(["a", "b", "c"])         # "a-b-c"
s[::-1]                           # "dlrow olleh"
"123".isdigit()                   # True
"abc".isalpha()                   # True
"abc123".isalnum()                # True
 
# --- built-ins ---
max(nums)
min(nums)
sum(nums)
sorted(nums)                      # returns new sorted list
sorted(nums, reverse=True)       # descending
sorted(nums, key=lambda x: -x)   # also descending
abs(-5)                           # 5
len(nums)
 
# --- any() and all() (short-circuit) ---
any([0, 0, 0])                    # False — nothing truthy
any([0, 0, 1])                    # True  — found one
all([1, 2, 3])                    # True  — all truthy
all([1, 0, 3])                    # False — 0 is falsy
any(x < 0 for x in nums)         # generator expression (preferred — lazy)
all(x > 0 for x in nums)
 
# --- map, filter, reduce ---
list(map(str, [1, 2, 3]))            # ["1", "2", "3"]
list(filter(lambda x: x > 2, nums))  # filter in one line
reduce(lambda a, b: a + b, nums)     # sum all
 
# --- common hackerrank patterns ---
lines = [input() for _ in range(n)]                           # read N lines
c = Counter([1, 1, 2, 3, 3, 3]); c.most_common(1)            # [(3, 3)]
d = defaultdict(list); d["key"].append(1)                     # no KeyError
sorted([("A", 90), ("B", 85)], key=lambda x: x[1], reverse=True)  # sort by key
list(permutations([1, 2, 3], 2))                              # all 2-length perms
list(combinations([1, 2, 3], 2))                              # all 2-length combos
 
# --- slicing [start:stop:step] ---
s = "abcdefgh"
s[2:5]      # "cde"
s[:3]       # "abc"
s[3:]       # "defgh"
s[-3:]      # "fgh"
s[::2]      # "aceg"
s[::-1]     # "hgfedcba"
s[1:6:2]    # "bdf"
 
# --- exception handling ---
try:
    x = int("abc")
except ValueError:
    print("not a number")
except Exception as e:
    print(f"error: {e}")
finally:
    print("always runs")
 
# --- file I/O ---
with open("file.txt", "r") as f:
    content = f.read()
with open("file.txt", "w") as f:
    f.write("hello")
 
# --- classes ---
class Dog:
    def __init__(self, name):
        self.name = name
    def bark(self):
        return f"{self.name} says woof"
d = Dog("Rex")
print(d.bark())
 
# --- one-liners ---
flat = [x for row in matrix for x in row]             # flatten 2D list
is_palindrome = s == s[::-1]                           # check palindrome
freq = {c: s.count(c) for c in set(s)}                # frequency count (no imports)
transposed = list(zip(*matrix))                        # transpose a matrix
nums = [int(input()) for _ in range(n)]                # read N lines as ints
most_common = max(set(lst), key=lst.count)             # most common element
seen = set()                                           # remove dupes, preserve order
unique = [x for x in lst if x not in seen and not seen.add(x)]

Terminology Worth Memorizing

These are official Python terms used throughout this post. If someone says them in an interview, you should know exactly what they mean.

TermWhat It IsExample
ComprehensionDeclarative way of describing a set.[x for x in iterable], {k: v for ...}
RangeLazy sequence of numbers, excluding the ceiling. Not a listrange(10) → 0 to 9, range(1, 6) → 1 to 5
List ComprehensionBuild a list in one expression[x for x in iterable]
Dict ComprehensionBuild a dict in one expression{k: v for k, v in items}
Generator ExpressionLazy comprehension, no brackets(x for x in iterable)
LambdaAnonymous functionlambda a, b: a + b
SlicingExtract subsequence by indexs[start:stop:step]
Tuple UnpackingAssign multiple values at oncea, b, c = (1, 2, 3)
Ternary ExpressionInline if/else (Conditional Expression)x if condition else y
f-stringFormatted string literalf"Hello, {name}"
IterableAnything you can loop overlist, tuple, set, dict, string, generator
IteratorObject that produces values lazilywhat map() returns
Short-circuit EvaluationStop early when result is knownany() stops at first True, all() stops at first False
Variadic ArgumentsAccept any number of args*args (positional), **kwargs (keyword)
Context ManagerAuto-cleanup with withwith open(...) as f:
Truthy / FalsyValues that evaluate to True or False0, "", [], None are falsy; everything else is truthy

Comprehension

"Comprehend" here means "to comprise," not "to understand."

A comprehension is the declarative way of describing a set.

The Structure

[output_expression for loop_variable in source]
  • output_expression — what gets placed into the resulting list. This is where you transform or pass through the value.
  • loop_variable — the name you give to each element as you iterate.
  • source — the iterable you're pulling values from.

Simplest Form

[x for x in range(10)]  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Pass through. Each x from the source goes straight into the output.

Modify the Output

Change the output expression to shape the result:

[x + 1 for x in range(10)]    # [1, 2, 3, ..., 10]
[x ** 2 for x in range(10)]   # [0, 1, 4, 9, ..., 81]
[x * -1 for x in range(10)]   # [0, -1, -2, ..., -9]
[str(x) for x in range(10)]   # ["0", "1", "2", ..., "9"]

The source is always the same — for x in range(10). The output expression on the left is where you decide what goes into the list.

From Math

It comes from math's set-builder notation:

{x² | x ∈ {0..9}}"the set of x squared, where x is in 0 through 9."

Python borrows the same structure:

[x ** 2 for x in range(10)]"x squared, for x between 0 to 9."

Same idea. Math uses |, Python uses for.

Imperative vs Declarative

Imperative — you describe how to build it, step by step:

squares = []
for x in range(10):
    squares.append(x ** 2)

Create an empty list. Loop. Calculate. Append. Repeat.

Declarative (comprehension) — you describe what it contains:

squares = [x ** 2 for x in range(10)]

One line. You define the set by its rule. Python figures out the rest.

Both produce [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]. The difference is that the comprehension reads like a definition, not a procedure.

Variants

[x for x in iterable]              # list comprehension
{k: v for k, v in items}           # dict comprehension
{x for x in iterable}              # set comprehension
(x for x in iterable)              # generator expression (lazy)

This is a living document. I will keep adding patterns as I solve more problems. The goal isn't to memorize — it's to internalize. When the webcam is on and the clock is ticking, your fingers should know where to go.