Write, run, and test Python code directly in your browser.
Online Python Runner
The runner above executes real Python in your browser, with no installation. This guide is about using it well: exactly what it can and cannot do, the standard library tools interview problems keep asking for, how to read input, how to debug without a debugger, how to talk about complexity, and nine exercises you can paste straight in.
It runs real Python in your browser using a build of CPython compiled to WebAssembly, so the language and the standard library behave normally. What it does not have is third party packages, network access, or access to files on your computer. That covers almost every coding interview problem and rules out data science and scripting work.
Because everything executes locally in the page, there is nothing to install and no server running your code. That is what makes it a good scratchpad: you can open it, paste a problem, and have an answer in under a minute. It also means the tab is doing the work, so a program with an infinite loop will freeze the page rather than time out politely.
The runner has three parts. The editor on the left holds your code and remembers it in your browser, so it is still there tomorrow. The input box on the right feeds standard input, which is what makes input() work. The output panel shows everything your program printed, once it has finished running.
It is worth being precise about the boundaries, because a browser based runner is not a smaller version of a local Python install, it is a different environment with a different shape. Knowing which is which saves you from concluding that your code is broken when it is the environment that cannot do the thing.
The language itself is complete. Classes, generators, comprehensions, decorators, context managers, f strings, type hints, exceptions, recursion, and the whole standard library behave the way they do anywhere else. So do collections, heapq, bisect, itertools, functools, math, random, re, json, datetime, and dataclasses. For interview problems, that is effectively everything you need.
Third party packages are not available. There is no numpy, no pandas, and no requests, and there is no way to install one from this page. If a problem needs a package, it is not an interview problem, it is engineering work, and it belongs in a local environment.
There is no network access. Anything that tries to open a socket or make an HTTP request will fail, because the code is running inside the browser's sandbox rather than on a machine with a network stack it can use. This is a security property rather than a bug.
File access is the one that surprises people. open() works, but it writes to an in browser virtual filesystem, not to your disk. You can write a file and read it back in the same run, which is occasionally useful, and it disappears when you reload the page. Your computer's files are not reachable from here at all.
Two execution details worth knowing. Output is collected while your program runs and shown all at once when it finishes, so it does not stream, and a long loop will look like nothing is happening. And execution is synchronous inside the page, so an infinite loop freezes the tab rather than timing out. If that happens, close the tab and reopen the page: your code is saved in the browser and will still be there.
A browser editor makes it easy to practise badly, by starting from a template and stopping once the code works. This is the loop that actually builds the skill an interview tests.
The Python runtime downloads the first time you open the page, and the editor is read only until it is ready. Once it unlocks, delete the sample code. Starting from an empty buffer matters more than it sounds: an interview starts from nothing, and practising from a template quietly removes the hardest part.
Before any logic, type the function definition and two or three example inputs with the answers you expect. This is the habit interviewers most want to see and the one candidates most often skip. It forces you to pin down what the function takes and returns, which is where a surprising number of interview failures actually begin.
One or two sentences naming the technique and the cost: I will use a hash map to count occurrences, which is linear time and linear space. This is exactly what you would say in an interview, and practising it here is free. If you cannot say it in one sentence, you do not have an approach yet and typing will not produce one.
Get something correct on the screen before you get something fast. A working solution you can check against your examples is a solid base to optimise from, and in a real interview a correct brute force with ten minutes left is a pass while a half finished optimal solution is not.
If the problem reads from standard input, put the input into the box on the right before you press run. input() reads one line per call, so the number of lines has to match the number of calls. This is the mechanic most people get wrong the first time and it takes one attempt to internalise.
There is no step debugger here, so debugging is done with print statements, and doing that well is a real skill. Print the state at the top of each loop iteration with a label, not just a value, so the output panel reads like a trace rather than a column of numbers.
Now improve it, and say what changed and why: replacing the inner scan with a set takes this from quadratic to linear time, at the cost of linear extra space. That sentence is the answer an interviewer is listening for, and rehearsing it here means you say it fluently when it counts.
This is the step that produces the improvement. Solving a problem once teaches you that problem. Solving it again from nothing, after you have forgotten the details, teaches you the pattern, and patterns are what transfer to the problem you have not seen.
Python is a common interview language for one main reason: a handful of standard library tools turn problems that need twenty lines in other languages into three or four. Knowing these fluently is worth more than knowing an extra algorithm, because they come up constantly and using them signals that you write Python rather than translating from another language.
From collections, four things. Counter counts occurrences in one call and gives you most_common for free, which covers frequency problems, anagram problems, and top k by count. defaultdict removes the entire class of bugs where you forget to initialise a key, which is what makes it the right structure for graph adjacency lists. deque gives you appends and pops from both ends in constant time, which is what breadth first search and sliding window problems require, because popping the front of a list is linear. namedtuple gives you a readable lightweight record when a tuple stops being self explanatory.
From heapq, the priority queue. It is a min heap on a plain list: heappush and heappop, plus nlargest and nsmallest for the common top k case. For a max heap, push the negated value, which is the standard idiom and worth practising until it stops feeling like a hack. Heaps are how you answer the k largest, merge k sorted lists, and scheduling families of questions.
From bisect, binary search over a sorted sequence without writing the loop. bisect_left and bisect_right give you the insertion point, and insort keeps a list sorted as you add to it. Most binary search interview questions are really questions about which of left and right you want at the boundary, and using the library forces you to think about that explicitly rather than getting it wrong in your own loop.
From itertools, the combinatorial generators: combinations, permutations, and product for exhaustive search, accumulate for running totals, groupby for runs of equal adjacent elements, and pairwise for consecutive pairs. From functools, lru_cache turns a recursive definition into a memoised one with a single decorator, which is the shortest path from a recurrence to a working dynamic programming solution.
Beyond the modules, the built ins that do real work: enumerate when you need the index and the value, zip to walk two sequences together, sorted with a key function, any and all for predicate checks, and sets for membership tests in constant time. A very large share of interview solutions are a set, a dictionary, and a single loop.
Standard input trips people up because two different conventions exist and problem statements rarely say which they are using. Some problems hand you arguments to a function. Others expect you to read lines from standard input. The runner supports the second through the input box on the right, and the mechanic is simple once you have seen it: whatever you type there becomes the lines your program reads, one line per call to input().
The classic shape is a count on the first line and the data after it. Read the count with n = int(input()), then loop n times reading a line each iteration. If your loop count does not match the number of lines you provided, you get an EOFError, which is actually a helpful error because it tells you exactly what is wrong.
Two patterns cover nearly everything else. For a line containing several numbers, split it and convert: nums = list(map(int, input().split())). For a grid, read the row count then read that many lines, keeping each one as a string or converting it to a list of characters, depending on whether you need to modify it. Strings are immutable in Python, so anything that mutates the grid needs lists.
Watch out for trailing whitespace and blank lines. Calling strip() on input you are going to compare or parse costs nothing and removes a category of bug that is genuinely hard to see, because a trailing space is invisible in the input box.
Finally, practise both conventions. Interview platforms differ, and arriving at a real interview unsure how to read input is an unforced way to lose five minutes at the start. If a problem gives you a function signature, write the function and call it yourself with hard coded examples. If it reads from input, use the box.
There is no step debugger in the browser, so print debugging is the tool, and there is a real difference between doing it well and scattering bare prints until something makes sense. Done well, it is fast enough that experienced engineers use it by choice.
Label everything. print(i) gives you a column of numbers with no context, while print('i', i, 'window', window, 'best', best) gives you a trace you can read like a table. Print at the top of each loop iteration rather than in several places, so the output has one line per iteration and the shape of the run is visible.
Print the shape of your data before you print its contents. A one line print of len(nums), type(nums[0]), and nums[:5] resolves a surprising share of bugs on its own, because most wrong answers come from the data being a different shape than you assumed rather than from the algorithm being wrong.
One specific thing about this runner: if your program raises an exception, the output panel shows the error instead of the prints that ran before it. That is worth knowing because it can look as though your prints never executed. If you need to see both, wrap the risky section in a try block and print inside the except branch, or comment out the line that raises while you inspect the state.
For recursion, print with indentation proportional to depth. Passing a depth parameter and printing ' ' * depth before your message turns an unreadable flat log into a visible call tree, which makes off by one errors in base cases obvious in seconds.
And when the bug will not surrender, shrink the input. Almost every bug that is invisible on a hundred element input is obvious on a three element one, and reducing the input is nearly always faster than reading the code again.
You will be asked for the time and space complexity of every solution you write, and the answer is expected in a specific vocabulary. It is a short vocabulary and it is worth being fluent rather than approximately right, because hesitating here reads as uncertainty about your own solution.
The ladder, from best to worst for a growing input: constant, logarithmic, linear, linear times logarithmic, quadratic, and exponential. In practice, constant means you did a fixed amount of work regardless of input size. Logarithmic means you halved the problem each step, which is binary search and balanced tree operations. Linear means you looked at each element a constant number of times. Linear times logarithmic is what sorting costs, and it is the cost of a heap based solution over all elements. Quadratic is a nested loop over the same input, and exponential is unpruned exhaustive search.
Two habits make this easy. First, state it as you write rather than reconstructing it afterwards, because the reason for each cost is fresh while you are writing the line that causes it. Second, always give both time and space, and say what the space is holding: linear extra space for the hash map, or constant extra space beyond the output.
The Python specific costs worth memorising, because they are where interview candidates go wrong: membership in a list is linear while membership in a set or dict is constant, appending to a list is amortised constant but inserting or popping at the front is linear, which is exactly why deque exists. Slicing a list copies it, so slicing inside a loop turns a linear algorithm quadratic without anything looking wrong. String concatenation in a loop is the same trap, and joining a list at the end is the fix.
Finally, know the difference between the complexity of your algorithm and the complexity of your implementation. They are frequently different, and the difference is almost always one of the Python costs above hiding inside an innocent looking line.
Each of these runs as written in the editor above. Work through them in order: they move from confirming the runner works to the standard library patterns that interview problems keep asking for. The hint under each one is the follow up question an interviewer would ask.
Paste this, put the word python on the first line of the input box, and press run. It confirms the runtime is loaded and that you understand how the input box feeds input().
word = input().strip()
print("reversed:", word[::-1])
print("letters:", len(word))
print("unique:", len(set(word)))Next: If you get an EOFError, the input box is empty. input() needs a line to read.
Frequency counting appears in anagram checks, top k problems, and duplicate detection. Counter does it in one call, and most_common gives you the ranking for free.
from collections import Counter
text = "the quick brown fox jumps over the lazy dog the end"
counts = Counter(text.split())
print(counts.most_common(3))
print("words seen once:", [w for w, c in counts.items() if c == 1])Next: Now do it without Counter, using a plain dict. Then say which is linear and why they both are.
The canonical example of trading space for time. The nested loop version is quadratic. Remembering what you have already seen makes it linear, and this trick generalises to a large family of problems.
def two_sum(nums, target):
seen = {}
for i, n in enumerate(nums):
if target - n in seen:
return (seen[target - n], i)
seen[n] = i
return None
print(two_sum([2, 7, 11, 15], 9))
print(two_sum([3, 2, 4], 6))
print(two_sum([1, 2], 100))Next: State the complexity out loud: linear time, linear space. Then handle duplicates in the input.
Windows are one of the highest frequency interview patterns. Recomputing the sum for each window is quadratic. Adding the new element and subtracting the old one keeps it linear.
def max_window_sum(nums, k):
if k > len(nums):
return None
window = sum(nums[:k])
best = window
for i in range(k, len(nums)):
window += nums[i] - nums[i - k]
best = max(best, window)
return best
print(max_window_sum([2, 1, 5, 1, 3, 2], 3))
print(max_window_sum([1], 1))
print(max_window_sum([1, 2], 5))Next: Add a print inside the loop showing i, window, and best. That trace is the whole algorithm.
Graph traversal with defaultdict for the adjacency list and deque for the queue. Using a list as a queue and popping from the front makes this quadratic, which is the mistake deque exists to prevent.
from collections import defaultdict, deque
edges = [("a", "b"), ("a", "c"), ("b", "d"), ("c", "d"), ("d", "e")]
graph = defaultdict(list)
for u, v in edges:
graph[u].append(v)
graph[v].append(u)
def shortest_path_length(start, goal):
queue = deque([(start, 0)])
seen = {start}
while queue:
node, dist = queue.popleft()
if node == goal:
return dist
for nxt in graph[node]:
if nxt not in seen:
seen.add(nxt)
queue.append((nxt, dist + 1))
return -1
print(shortest_path_length("a", "e"))
print(shortest_path_length("a", "a"))Next: Mark nodes as seen when you enqueue them, not when you dequeue them, or you will visit some twice.
Sorting everything to take k elements costs linear times logarithmic in the whole input. A heap of size k costs the input size times the logarithm of k, which matters when k is small and the input is large.
import heapq
nums = [5, 1, 9, 3, 14, 7, 11, 2]
def top_k(values, k):
heap = []
for v in values:
heapq.heappush(heap, v)
if len(heap) > k:
heapq.heappop(heap)
return sorted(heap, reverse=True)
print(top_k(nums, 3))
print(heapq.nlargest(3, nums))Next: heapq is a min heap, which is why keeping the k largest means popping the smallest. Now write the k smallest version.
Most binary search questions are really about which boundary you want. bisect_left and bisect_right make that choice explicit instead of leaving it to an off by one in your own loop.
import bisect
sorted_nums = [1, 2, 2, 2, 5, 8, 13]
print("first index of 2:", bisect.bisect_left(sorted_nums, 2))
print("index after last 2:", bisect.bisect_right(sorted_nums, 2))
print("count of 2s:", bisect.bisect_right(sorted_nums, 2) - bisect.bisect_left(sorted_nums, 2))
print("insert position for 6:", bisect.bisect_left(sorted_nums, 6))Next: Now write bisect_left yourself with a while loop. Getting the boundary right is the whole exercise.
The shortest route from a recurrence to a working dynamic programming solution. Write the naive recursion, add one decorator, and the exponential version becomes linear.
from functools import lru_cache
@lru_cache(maxsize=None)
def ways_to_climb(n):
if n < 0:
return 0
if n == 0:
return 1
return ways_to_climb(n - 1) + ways_to_climb(n - 2)
for i in range(1, 11):
print(i, ways_to_climb(i))
print("n=60:", ways_to_climb(60))Next: Remove the decorator and try n=35. The pause is the difference between exponential and linear.
The standard competitive and interview platform input shape: a count, then that many lines. Put 4 on the first line of the input box and four numbers on the lines after it.
n = int(input())
nums = [int(input()) for _ in range(n)]
print("count:", n)
print("sum:", sum(nums))
print("max:", max(nums))
print("sorted:", sorted(nums))Next: If you get an EOFError, your count and the number of lines disagree. That error is a feature.
Neither one is better in general. They are good at different jobs, and knowing the boundary is what stops you wasting an afternoon on something the browser cannot do.
| What you want to do | This browser runner | A local Python install |
|---|---|---|
| Solve a coding interview problem | Ideal. One file, no dependencies, no setup | Works, but the setup is friction you do not need |
| Check a piece of language behaviour | Ideal. Faster than opening anything else | Fine, if a shell is already open |
| Use numpy, pandas, or requests | Not possible. No packages can be installed | The right choice |
| Read a data file from your disk | Not possible. The filesystem is in browser only | The right choice |
| Step through code with breakpoints | Not available. Debug with labelled prints | The right choice |
| Run tests, linting, and version control | Not available | The right choice |
| Long running or heavy computation | Poor. It freezes the tab while it runs | The right choice |
A browser runner is the right tool for a specific job: short programs, interview problems, quick checks of language behaviour, and teaching. It is the wrong tool for several others, and recognising the boundary saves time.
Move to a local install as soon as you need a package. Anything involving numerical work, data analysis, HTTP requests, a web framework, or a database needs libraries this runner cannot install, and fighting that is wasted effort rather than a challenge to solve.
Move locally when you need real files. Reading a large data file from your disk, writing output you want to keep, or working across multiple modules in a project are all things the in browser filesystem is not for.
Move locally when you need proper tooling. A step debugger with breakpoints, a test runner, a linter and formatter wired into your editor, and version control are what make longer work sustainable, and none of them exist here. If a program is more than about a hundred lines, you are past the point where a single buffer is helping you.
And move locally when performance matters. WebAssembly is fast but it is not a native install, and anything long running is better on your own machine where it can use full resources and where you can leave it going without holding a browser tab open.
The workflow that works well is to use both. Sketch here, because it is quicker than opening anything. Once the sketch turns into something you want to keep, move it into a real project with tests and version control. For interview preparation specifically, you may never need to leave, since almost every coding interview problem fits comfortably in a single file with no dependencies, which is exactly what this page runs best.
Yes. There is no account, no sign up, and no limit on how many times you run your code.
Everything on the page works immediately once the Python runtime has finished loading, which happens the first time you open it.
It runs inside your browser tab, using a build of CPython compiled to WebAssembly. Your code is not sent anywhere to be executed.
The editor also keeps your code in your browser's local storage so it is still there when you come back. That copy stays on your machine.
No. Only the Python standard library that ships with the runtime is available, and there is no way to install a third party package from this page.
The standard library is enough for essentially every coding interview problem, since collections, heapq, bisect, itertools, functools, math, re, and json are all present. For anything that needs a package, use a local Python install.
Yes. input() reads from the input box on the right, one line per call, so fill the box in before you press run.
If you call input() more times than there are lines in the box, you get an EOFError. That is usually a sign that your loop count does not match the input you provided.
open() works, but it reads and writes an in browser virtual filesystem rather than your computer's disk. You can write a file and read it back within the same run.
Anything you write there is discarded when you reload the page, and files on your own machine are not reachable from the runner at all.
No. The runner has no network access, so anything that opens a socket or makes an HTTP request will fail.
That is a property of running inside the browser's sandbox rather than a limitation we added, and it is the reason the runner is safe to use with no account.
Output is collected while your program runs and shown all at once at the end, so it does not stream. A long loop will look as though nothing is happening until it completes.
Keep debug traces small enough to read for this reason, and print once per loop iteration rather than in several places.
When your code raises an exception, the output panel shows the error rather than the output that was produced before it. It can look as though your prints never ran.
If you need both, wrap the risky section in a try block and print inside the except branch, or comment out the line that raises while you inspect the state.
Almost certainly an infinite loop. Execution is synchronous inside the page, so a loop that never ends locks up the tab rather than timing out.
Close the tab and reopen the page. Your code is saved in the browser, so you will get it back, and then add a print inside the loop to see where it is not terminating.
Yes, and for that specific purpose it is arguably better than a local setup, because there is no friction between deciding to practise and starting. Almost every coding interview problem is one file with no dependencies, which is exactly what this runs.
The one thing to be deliberate about is starting from an empty editor rather than a template, because starting from nothing is the part a real interview tests.
collections for Counter, defaultdict, and deque. heapq for priority queues and top k. bisect for binary search boundaries. itertools for combinations, permutations, product, and groupby. functools for lru_cache.
Alongside those, the built ins that do the most work: enumerate, zip, sorted with a key function, any, all, and sets for constant time membership tests.
As soon as you need a third party package, real files on your disk, a project with several modules, a step debugger, a test runner, or version control.
Also switch for anything long running or performance sensitive. WebAssembly is fast, but your own machine is faster and does not need a browser tab left open.
It runs in any modern browser, and there is a run button positioned for smaller screens.
Writing more than a few lines of code on a phone keyboard is uncomfortable, so for real practice use the largest screen you have.
A runner makes you quick at writing code. These are the pages that make you good at the interview around it.
A live course from the start, if you are still looking things up for every line you write.
The language patterns interview problems need, including the standard library shortcuts on this page.
The algorithms the exercises above are practising, taught in an order that builds.
The other half of a technical loop, from requirements through storage choices to tradeoffs.
Build applications with language models, retrieval, and agents, once the fundamentals are in place.
Every HireCade course in one place.
Twenty minute spoken practice interviews with written feedback, because interviews test talking as well as coding.
Sixty minute sessions with engineers and hiring managers, with feedback and a recording.
Questions by role and company, so you can pick problems that match the loop you are facing.
A blank canvas for sketching a data structure before you code it, and for design rounds.
Ask what the coding round at your target company actually looks like.
Free builder with a live preview and PDF export, plus a guide to structure and bullet points.
The whole path in order: learn, practise, build a resume, apply, interview, and negotiate.
How titles map to levels across companies, which tells you how hard a coding round will push.
Compensation ranges by role and company, for the conversation after the interviews.
Longer articles on interviews, hiring, and engineering careers.
Guides and reference material collected by topic.