How to Trick People Into Hiring You With Python

Code interviews are stressful. It doesn’t matter if you’re a pro, it doesn’t matter if you’re overqualified, it doesn’t even matter if you don’t need the job. Proving that you’re competent is always intimidating.

The good news is you’re probably much more competent than you think you are, you’re just possibly not as good at demonstrating it as you’d like to be. Python makes it pretty easy. And you might actually improve your production code along the way.

I’m not going to cover basic interview tips, like explaining your thought process and starting with the naive solution, because they’re covered in a million other articles. Instead, we’re going to focus on things that can make a candidate interviewing in Python look super slick.

As a quick aside, if you aren’t interviewing in Python, in my opinion, you should work on that. Everyone says to interview in the language you’re most comfortable in, and that’s absolutely true. So get comfortable in Python. It’s terse, it’s clean, it’s elegant, and it gives you 3 opportunities on every line to look smart. If you have the time and the base knowledge to learn Python well enough in time to interview in, do it. Just make sure you have a few months to get very comfortable.

Comprehensions

If you’re not using list comprehensions, you’re not totally writing Python yet. It’s a fantastic piece of syntactic sugar for doing maps and filters. For the uninitiated:

# How first timers do it:
evens = []
for x in range(10):
    squares.append(2*x)

# Once you learn about map: 
squares = list(map(lambda x: x**2, range(10)))
# Note that map returns an iterator,
# so we have to explicitly make it a list

# With comprehensions:
cubes = [x**3 for x in range(10)]

# Just the odd ones now:
odd_cubes [x**3 for x in range(10) if x % 0]
# The if statement at the end is like adding
# a filter to our map

What’s more, there are also set and dictionary comprehensions. And they’re just as easy, and nearly as useful.

# Set comprehension:
nums = {x for x in [1, 2, 3, 1, 2, 3, 4]}
// {1, 2, 3, 4}

# Dictionary comprehension:
text_to_num = {str(x):x for x in range(5)}
// {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}

You can also use any of these comprehensions as a for-each, if you don’t care about the resulting list. Strictly speaking, this can be a dangerous practice, as it generally indicates you’re creating side effects, or altering the list in place, which is a no no in most cases, but it is possible.

If your interviewer isn’t super experienced in Python, you may be asked to politely explain this syntax. Which is a good thing. Explain that it’s elegant syntactic sugar for a map that allows the interpreter to do some optimizations. So, basically, it’s easier to read and faster. Interviewers like seeing that you’re intimately familiar with the features of your language of choice. It means you’re better prepared to learn whichever one they need you to learn.

The Python Standard Library: The Fun Parts

Ok, you got asked to write a Fibonacci number generator in your interview. You made a nice pretty recursive implementation, and you’re going to convert it to a dynamic programming implementation because no one wants slow Fibonacci numbers, but the interviewer stops you.

def fibonacci(n):
    if n < 1:
         return 0
    if n == 1:
         return 1
    return fibonacci(n-1) + fibonacci(n-2)

“Before we switch the implementation, is there anything we can do to make this implementation faster?”

-An interviewer that just wants to see you iterate, and doesn’t care that you read Cracking the Coding Interview

Oh boy. Uh, memoization, right? That should be simple enough, let’s just add a dictionary outside it and… uh oh. We’re dirtying our beautiful simple function definition and using an arbitrary amount of memory. Ok, I guess we’ll just create a class or at least a function to manage the cache and its size and…

Stop. This is something that we need to do in programming all the time. So you bet your butt the standard library did it for you. Enter functools.lru_cache.

from functools import lru_cache

@lru_cache
def fibonacci(n):
    if n < 1:
         return 0
    if n == 1:
         return 1
    return fibonacci(n-1) + fibonacci(n-2)

That’s it. Done. This function will now magically remember what’s returned for a given input. Inputs all have to be hashable, and the function has to be pure/deterministic, but that’s really it. Default cache size is capped at 128, but you can change that if you want.

This is just one simple example of what functools and itertools can offer you. They are, hands down, the two most awesome parts of the Python Standard Library in my opinion. Go read the documentation for them, and write some scratch code that uses every part of them at least once. One day, you’ll catch yourself saying, “Whoa, this question is basically just plain solved for me by the standard library.” And you’ll get a job from someone else’s work, totally legally.

Easy Generators

Ok, itertools isn’t always going to have what you need, sure. But you may be able to create an iterator of your own. What are the magic methods we need to implement again? Man, you should’ve memorized those before this interview.

Or just do it the easy way: the yield keyword. You’d be surprised how many problems can be done elegantly and succinctly with a custom generator. And it’s very Pythonic.

Remember that Fibonacci function? Here it is in generator form.

def fibgen(n):
    a, b = 0, 1
    for _ in range(n):
        yield b
        a, b = b, a + b

All the fibs you need.

Knock It Off With the Classes

Coders over use classes, especially in interviews. I’ve seen interviewees start solving a simple text manipulation problem by implementing a custom class as their very first step, before even thinking about the solution.

That’s not awesome.

Classes are great. They are useful. They encapsulate the relationship between behavior and data beautifully. You should be intimately familiar with how they work in python. You should know all about classes and dunder methods. You should know how to make a class hashable so you can stick it in a set. You should be ready to use them on the job, and possibly in interviews. But if you spend half the time you have with the interviewer typing and correcting boilerplate just to demonstrate you know how to write a class, they’re going to be less confident in your ability then they could’ve been.

If you’re writing a class with one method and only a couple properties, you just put two variables and a function inside the class keyword for no reason. Python is not C++; refactoring is super easy here. So start with a built-in type and a function. If you need to move to a class later, do it. But you probably won’t for a problem that you’re coding in 15 minutes.

In short: Unless the question says to implement a class, class should not be the first word you type when you start coding.

Be Super Pythonic, Then Do It the Harder/Faster Way

Start with the super-duper Pythonic way. Wow them with your newfound knowledge of comprehensions, the standard library, and generators. Explain why this is an elegant and efficient solution, and in practice, the one that you would always use in production. The big O notation is already as spicy as it’s going to get. If speed were enough of a concern to optimize past this point, then it’s time to switch to a compiled language. That isn’t actually necessarily true, but senior C++ devs love to hear it all the same.

Now it’s time to do it wrong. Chances are, your interviewers aren’t Python whizzes like you. Maybe they know some Python, maybe they don’t, but unless you’re interviewing for a Python roll, they might feel cheated by your usage of the built-in lru_cache. Or they want you to optimize even further, which requires using some manual for looping instead of a list comprehension. Even if they don’t say any of these things out loud, you should vocalize that you can make it faster (if you can, of course), or that you can pretend Angus never told you about lru_cache and do the memoization manually for the sake of the interview.

In fact, in some interviews, I’ve offered that up front before I even solve the problem. One problem revolved around finding all possible permutations of pairs of elements in a list. So I said the standard library makes this trivial, but I can pretend not to have that if they’d like. They said the standard library was fair game. So I used it…

from itertools import permutations

def solution(arr):
    return list(permutations(arr, 2))

That one got a laugh. Again I offered to implement it by hand, because, obviously, this demonstrates nothing about my ability to solve problems. However, it absolutely demonstrates my familiarity and willingness to use the standard library, which is surprisingly rare. Fortunately, there was also more to this problem, so I was able to show some skills after this first step.

Relax

The single most important piece of advice I can give. Being nervous does not help you. Stressing over the interview will make you perform worse, if anything. Either you’re capable of what they want to see in that short window, or you are not. It’s not actually a reflection of your intelligence, or even your ability. It’s just a reflection of whether you passed their arbitrary standard.

Essentially: You already meet the requirements (or you don’t, and won’t by then). Treat the interview like a victory lap, waving your nerd flag around. Be excited. Be confident, but stop short of arrogant. It costs nothing, and interviewers want to hire people they like. Maybe even more than they want to hire smart people.

And if that last bit isn’t true, I’m not sure how I ever got a job.

Good luck.

Leave a Reply

Your email address will not be published. Required fields are marked *