You’ve made it past the phone call with the recruiter, and now it’s time to show that you know how to solve problems with actual code. Whether it’s a HackerRank exercise, a take-home assignment, or an onsite whiteboard interview, this is your moment to prove your coding interview skills. Show
But interviews aren’t just about solving problems: they’re also about showing that you can write clean production code. This means that you have a deep knowledge of Python’s built-in functionality and libraries. This knowledge shows companies that you can move quickly and won’t duplicate functionality that comes with the language just because you don’t know it exists. Note: To get a feel for how a coding interview might go and to learn best practices for coding challenges, check out the video course Write and Test a Python Function: Interview Practice. At Real Python, we’ve put our heads together and discussed what tools we’re always impressed to see in coding interviews. This article will walk you through the best of that functionality, starting with Python built-ins, then Python’s native support for data structures, and finally Python’s powerful (and often underappreciated) standard library. In this article, you’ll learn how to:
Free Bonus: 5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you’ll need to take your Python skills to the next level. Select the Right Built-In Function for the JobPython has a large standard library but only a small library of built-in functions, which are always available and don’t need to be imported. It’s worth going through each one, but until you get the chance to do so, here are a few built-in functions worth understanding how to use, and in the case of some of them, what alternatives to use instead. Remove adsIterate With >>> numbers = [45, 22, 14, 65, 97, 72] >>> for i, num in enumerate(numbers, start=52): ... print(i, num) ... 52 45 53 22 54 14 55 65 56 97 57 72 7 Instead of >>> numbers = [4, 2, 1, 6, 9, 7] >>> def square(x): ... return x*x ... >>> list(map(square, numbers)) [16, 4, 1, 36, 81, 49] >>> [square(x) for x in numbers] [16, 4, 1, 36, 81, 49] 1This scenario might come up more than any other in coding interviews: you have a list of elements, and you need to iterate over the list with access to both the indices and the values. There’s a classic coding interview question named FizzBuzz that can be solved by iterating over both indices and values. In FizzBuzz, you are given a list of integers. Your task is to do the following:
Often, developers will solve this problem with 1:>>>
Range allows you to access the elements of 0 by index and is a useful tool for some situations. But in this case, where you want to get each element’s index and value at the same time, a more elegant solution uses 7:>>>
For each element, 7 returns a counter and the element value. The counter defaults to 3, which conveniently is also the element’s index. Don’t want to start your count at 3? Just use the optional 5 parameter to set an offset:>>>
By using the 5 parameter, we access all of the same elements, starting with the first index, but now our count starts from the specified integer value.Use List Comprehensions Instead of >>> def is_odd(x): ... return bool(x % 2) ... >>> list(filter(is_odd, numbers)) [1, 9, 7] >>> [x for x in numbers if is_odd(x)] [1, 9, 7] 7 and >>> def is_odd(x): ... return bool(x % 2) ... >>> list(filter(is_odd, numbers)) [1, 9, 7] >>> [x for x in numbers if is_odd(x)] [1, 9, 7] 8
He may have been wrong about it being uncontroversial, but Guido had good reasons for wanting to remove 7 and 8 from Python. One reason is that Python supports list comprehensions, which are often easier to read and support the same functionality as 7 and 8.Let’s first take a look at how we’d structure a call to 7 and the equivalent list comprehension:>>>
Both approaches, using 7 and the list comprehension, return the same values, but the list comprehension is easier to read and understand.Now we can do the same thing for the 8 and its equivalent list comprehension:>>>
Like we saw with 7, the 8 and list comprehension approaches return the same value, but the list comprehension is easier to follow.Developers who come from other languages may disagree that list comprehensions are easier to read than 7 and 8, but in my experience beginners are able to pick up list comprehensions much more intuitively.Either way, you’ll rarely go wrong using list comprehensions in a coding interview, as it will communicate that you know what’s most common in Python. Remove adsDebug With >>> numbers = [45, 22, 14, 65, 97, 72] >>> for i, num in enumerate(numbers, start=52): ... print(i, num) ... 52 45 53 22 54 14 55 65 56 97 57 72 8 Instead of import pdb; pdb.set_trace() 1You may have debugged a small problem by adding 1 to your code and seeing what was printed out. This approach works well at first but quickly becomes cumbersome. Plus, in a coding interview setting, you hardly want 1 calls peppered throughout your code.Instead, you should be using a debugger. For non-trivial bugs, it’s almost always faster than using 1, and given that debugging is a big part of writing software, it shows that you know how to use tools that will let you develop quickly on the job.If you’re using Python 3.7, you don’t need to import anything and can just call at the location in your code where you’d like to drop into the debugger:
Calling 8 will put you into 7, which is the default Python debugger. On Python 3.6 and older, you can do the same by importing 7 explicitly:
Like 8, 0 will put you into the 7 debugger. It’s just not quite as clean and is a tad more to remember.There are other debuggers available that you may want to try, but 7 is part of the standard library, so it’s always available. Whatever debugger you prefer, it’s worth trying them out to get used to the workflow before you’re in a coding interview setting.Format strings With f-StringsPython has a lot of different ways to handle string formatting, and it can be tricky to know what to use. In fact, we tackle formatting in depth in two separate articles: one about string formatting in general and one specifically focused on f-strings. In a coding interview, where you’re (hopefully) using Python 3.6+, the suggested formatting approach is Python’s f-strings. f-strings support use of the , as well as powerful string interpolation. These features allow you to add variables or even valid Python expressions and have them evaluated at runtime before being added to the string: >>>
The f-string allows you to put 3 into the string and add her age with the desired formatting in one succinct operation.The one risk to be aware of is that if you’re outputting user-generated values, then that can introduce security risks, in which case may be a safer option. Sort Complex Lists With >>> def get_name_and_decades(name, age): ... return f"My name is {name} and I'm {age / 10:.5f} decades old." ... >>> get_name_and_decades("Maria", 31) My name is Maria and I'm 3.10000 decades old. 4Plenty of coding interview questions require some kind of sorting, and there are multiple valid ways you can sort items. Unless the interviewer wants you to implement your own sorting algorithm, it’s usually best to use 4.You’ve probably seen the most simple uses of sorting, such as sorting lists of numbers or strings in ascending or descending order: >>>
By default, 4 has sorted the input in ascending order, and the 7 keyword argument causes it to sort in descending order.It’s worth knowing about the optional keyword argument 8 that lets you specify a function that will be called on every element prior to sorting. Adding a function allows custom sorting rules, which are especially helpful if you want to sort more complex data types:>>>
By passing in a lambda function that returns each element’s age, you can easily sort a list of dictionaries by a single value of each of those dictionaries. In this case, the dictionary is now sorted in ascending order by age. Remove adsLeverage Data Structures EffectivelyAlgorithms get a lot of attention in coding interviews, but data structures are arguably even more important. In a coding interviewing context, picking the right data structure can have a major impact on performance. Beyond theoretical data structures, Python has powerful and convenient functionality built into its standard data structure implementations. These data structures are incredibly useful in coding interviews because they give you lots of functionality by default and let you focus your time on other parts of the problem. Store Unique Values With SetsYou’ll often need to remove duplicate elements from an existing dataset. New developers will sometimes do so with lists when they should be using sets, which enforce the uniqueness of all elements. Pretend you have a function named 9. It will always return a random selection from a small set of words:>>> 0You’re supposed to call 9 repeatedly to get 1000 random words and then return a data structure containing every unique word. Here are two common, suboptimal approaches and one good approach.Bad Approach 1 stores values in a list then converts the list into a set:>>> 1This approach isn’t terrible, but it unnecessarily creates a list and then converts it to a set. Interviewers almost always notice (and ask about) this type of design choice. Worse Approach To avoid converting from a list to a set, you now store values in a list without using any other data structures. You then test for uniqueness by comparing new values with all elements currently in the list: >>> 2This is worse than the first approach, because you have to compare every new word against every word already in the list. That means that as the number of words grows, the number of lookups grows quadratically. In other words, the time complexity grows on the order of O(N²). Good Approach Now, you skip using lists altogether and instead use a set from the start: >>> 3This may not look much different than the other approaches except for making use of a set from the beginning. If you consider what’s happening within 2, it even sounds like the second approach: get the word, check if it’s already in the set, and if not, add it to the data structure.So why is using a set different from the second approach? It’s different because sets store elements in a manner that allows near-constant-time checks whether a value is in the set or not, unlike lists, which require linear-time lookups. The difference in lookup time means that the time complexity for adding to a set grows at a rate of O(N), which is much better than the O(N²) from the second approach in most cases. Remove adsSave Memory With GeneratorsList comprehensions are convenient tools but can sometimes lead to unnecessary memory usage. Imagine you’ve been asked to find the sum of the first 1000 perfect squares, starting with 1. You know about list comprehensions, so you quickly code up a working solution: >>> 4Your solution makes a list of every perfect square between 1 and 1,000,000 and sums the values. Your code returns the right answer, but then your interviewer starts increasing the number of perfect squares you need to sum. At first, your function keeps popping out the right answer, but soon it starts slowing down until eventually the process seems to hang for an eternity. This is the last thing you want happening in a coding interview. What’s going on here? It’s making a list of every perfect square you’ve requested and summing them all. A list with 1000 perfect squares may not be large in computer-terms, but 100 million or 1 billion is quite a bit of information and can easily overwhelm your computer’s available memory resources. That’s what’s happening here. Thankfully, there’s a quick way to solve the memory problem. You just replace the brackets with parentheses: >>> 5Swapping out the brackets changes your list comprehension into a generator expression. Generator expressions are perfect for when you know you want to retrieve data from a sequence, but you don’t need to access all of it at the same time. Instead of creating a list, the generator expression returns a 3 object. That object knows where it is in the current state (for example, 4) and only calculates the next value when it’s asked for.So when 5 iterates over the generator object by calling 6 repeatedly, the generator checks what 7 equals, calculates 8, increments 7 internally, and returns the proper value to 5. The design allows generators to be used on massive sequences of data, because only one element exists in memory at a time.Define Default Values in Dictionaries With >>> animals = [ ... {'type': 'penguin', 'name': 'Stephanie', 'age': 8}, ... {'type': 'elephant', 'name': 'Devon', 'age': 3}, ... {'type': 'puma', 'name': 'Moe', 'age': 5}, ... ] >>> sorted(animals, key=lambda animal: animal['age']) [ {'type': 'elephant', 'name': 'Devon', 'age': 3}, {'type': 'puma', 'name': 'Moe', 'age': 5}, {'type': 'penguin', 'name': 'Stephanie, 'age': 8}, ] 1 and >>> animals = [ ... {'type': 'penguin', 'name': 'Stephanie', 'age': 8}, ... {'type': 'elephant', 'name': 'Devon', 'age': 3}, ... {'type': 'puma', 'name': 'Moe', 'age': 5}, ... ] >>> sorted(animals, key=lambda animal: animal['age']) [ {'type': 'elephant', 'name': 'Devon', 'age': 3}, {'type': 'puma', 'name': 'Moe', 'age': 5}, {'type': 'penguin', 'name': 'Stephanie, 'age': 8}, ] 2One of the most common programming tasks involves adding, modifying, or retrieving an item that may or may not be in a dictionary. Python dictionaries have elegant functionality to make these tasks clean and easy, but developers often check explicitly for values when it isn’t necessary. Imagine you have a dictionary named 3, and you want to get that cowboy’s name. One approach is to explicitly check for the key with a conditional:>>> 6This approach first checks if the 4 key exists in the dictionary, and if so, it returns the corresponding value. Otherwise, it returns a default value.While explicitly checking for keys does work, it can easily be replaced with one line if you use 1:>>> 7 6 performs the same operations that were performed in the first approach, but now they’re handled automatically. If the key exists, then the proper value will be returned. Otherwise, the default value will get returned.But what if you want to update the dictionary with a default value while still accessing the 4 key? 1 doesn’t really help you here, so you’re left with explicitly checking for the value again:>>> 8Checking for the value and setting a default is a valid approach and is easy to read, but again Python offers a more elegant method with 2:>>> 9 2 accomplishes exactly the same thing as the snippet above. It checks if 4 exists in 3, and if so it returns that value. Otherwise, it sets 03 to 04 and returns the new value.Remove adsTake Advantage of Python’s Standard LibraryBy default, Python comes with a lot of functionality that’s just an 05 statement away. It’s powerful on its own, but knowing how to leverage the standard library can supercharge your coding interview skills.It’s hard to pick the most useful pieces from all of the available modules, so this section will focus on just a small subset of its utility functions. Hopefully, these will prove useful to you in coding interviews and also whet your appetite to learn more about the advanced functionality of these and other modules. Handle Missing Dictionary Keys With >>> numbers = [45, 22, 14, 65, 97, 72] >>> for i, num in enumerate(numbers): ... if num % 3 == 0 and num % 5 == 0: ... numbers[i] = 'fizzbuzz' ... elif num % 3 == 0: ... numbers[i] = 'fizz' ... elif num % 5 == 0: ... numbers[i] = 'buzz' ... >>> numbers ['fizzbuzz', 22, 14, 'buzz', 97, 'fizz'] 06 1 and 2 work well when you’re setting a default for a single key, but it’s common to want a default value for all possible unset keys, especially when programming in a coding interview context.Pretend you have a group of students, and you need to keep track of their grades on homework assignments. The input value is a list of tuples with the format 09, but you want to easily look up all the grades for a single student without iterating over the list.One way to store the grade data uses a dictionary that maps student names to lists of grades: >>> 0In this approach, you iterate over the students and check if their names are already properties in the dictionary. If not, you add them to the dictionary with an empty list as the default value. You then append their actual grades to that student’s list of grades. But there’s an even cleaner approach that uses a 10, which extends standard 11 functionality to allow you to set a default value that will be operated upon if the key doesn’t exist:>>> 1In this case, you’re creating a 10 that uses the 13 constructor with no arguments as a default factory method. 13 with no arguments returns an empty list, so 10 calls 13 if the name doesn’t exist and then allows the grade to be appended. If you want to get fancy, you could also use a lambda function as your factory value to return an arbitrary constant.Leveraging a 10 can lead to cleaner application code because you don’t have to worry about default values at the key level. Instead, you can handle them once at the 10 level and afterwards act as if the key is always present. For more information on this technique, check out Using the Python defaultdict Type for Handling Missing Keys.Count Hashable Objects With >>> numbers = [45, 22, 14, 65, 97, 72] >>> for i, num in enumerate(numbers, start=52): ... print(i, num) ... 52 45 53 22 54 14 55 65 56 97 57 72 9You have a long string of words with no punctuation or capital letters and you want to count how many times each word appears. You could use a dictionary or 10 and increment the counts, but 9 provides a cleaner and more convenient way to do exactly that. Counter is a subclass of 11 that uses 3 as the default value for any missing element and makes it easier to count occurrences of objects:>>> 2When you pass in the list of words to 24, it stores each word along with a count of how many times that word occurred in the list.Are you curious what the two most common words were? Just use 25:>>> 3 25 is a convenience method and simply returns the 27 most frequent inputs by count.Remove adsAccess Common String Groups With >>> numbers = [45, 22, 14, 65, 97, 72] >>> for i, num in enumerate(numbers): ... if num % 3 == 0 and num % 5 == 0: ... numbers[i] = 'fizzbuzz' ... elif num % 3 == 0: ... numbers[i] = 'fizz' ... elif num % 5 == 0: ... numbers[i] = 'buzz' ... >>> numbers ['fizzbuzz', 22, 14, 'buzz', 97, 'fizz'] 28 ConstantsIt’s trivia time! Is 29 true or false?It’s false, because the ASCII code for 30 is 65, but 31 is 97, and 65 is not greater than 97.Why does the answer matter? Because if you want to check if a character is part of the English alphabet, one popular way is to see if it’s between 30 and 33 (65 and 122 on the ASCII chart).Checking the ASCII code works but is clumsy and easy to mess up in coding interviews, especially if you can’t remember whether lowercase or uppercase ASCII characters come first. It’s much easier to use the constants defined as part of the 28 module.You can see one in use in 35, which returns whether all characters in a string are uppercase letters:>>> 4 35 iterates over the letters in 37, and checks if the letters are part of 38. If you print out 38 you’ll see that it’s just a lowly string. The value is set to the literal 40.All 28 constants are just strings of frequently referenced string values. They include the following:
These are easier to use and, even more importantly, easier to read. Generate Permutations and Combinations With >>> numbers = [45, 22, 14, 65, 97, 72] >>> for i, num in enumerate(numbers): ... if num % 3 == 0 and num % 5 == 0: ... numbers[i] = 'fizzbuzz' ... elif num % 3 == 0: ... numbers[i] = 'fizz' ... elif num % 5 == 0: ... numbers[i] = 'buzz' ... >>> numbers ['fizzbuzz', 22, 14, 'buzz', 97, 'fizz'] 51Interviewers love to give real life scenarios to make coding interviews seem less intimidating, so here’s a contrived example: you go to an amusement park and decide to figure out every possible pair of friends that could sit together on a roller coaster. Unless generating these pairs is the primary purpose of the interview question, it’s likely that generating all the possible pairs is just a tedious step on the way towards a working algorithm. You could calculate them yourself with nested for-loops, or you could use the powerful 51 library. 51 has multiple tools for generating iterable sequences of input data, but right now we’ll just focus on two common functions: 54 and 55. 54 builds a list of all permutations, meaning it’s a list of every possible grouping of input values with a length matching the 57 parameter. The 58 keyword argument lets us specify how many values go in each grouping:>>> 5With permutations, the order of the elements matters, so 59 represents a different pairing than 60, meaning that they would both be included in the list. 55 builds combinations. These are also the possible groupings of the input values, but now the order of the values doesn’t matter. Because 59 and 60 represent the same pair, only one of them would be included in the output list:>>> 6Since the order of the values does not matter with combinations, there are fewer combinations than permutations for the same input list. Again, because we set 58 to 2, each grouping has two names in it. 65 and 66 are just small examples of a powerful library, but even these two functions can be quite useful when you’re trying to solve an algorithm problem quickly.Remove adsConclusion: Coding Interview SuperpowersYou can now feel comfortable using some of Python’s less common, but more powerful, standard features in your next coding interview. There’s a lot to learn about the language as a whole but this article should have given you a starting point to go deeper while letting you use Python more effectively when you interview. In this article, you’ve learned different types of standard tools to supercharge your coding interview skills:
Interviewing may not be the best approximation of real software development, but it’s worth knowing how to succeed in any programming environment, even interviews. Thankfully, learning how to use Python during coding interviews can help you understand the language more deeply, which will pay dividends during day-to-day development. Mark as Completed Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Python Coding Interviews: Tips & Best Practices 🐍 Python Tricks 💌 Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team. Send Me Python Tricks » About James Timmins James is a software consultant and Python developer. When he's not writing Python, he's usually writing about it in blog or book form. » More about JamesEach tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are: Aldren Geir Arne Joanna Master Real-World Python Skills With Unlimited Access to Real Python Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas: Level Up Your Python Skills » Master Real-World Python Skills Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas: Level Up Your Python Skills » What Do You Think? Rate this article: Tweet Share Share EmailWhat’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know. Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. and get answers to common questions in our support portal. |