FullStack Labs is a leading team of Python developers, engineers, programmers, coders, and architects. Uber, Siemens, and hundreds of other companies have chosen us for their mission critical software development projects.
We’ll review your code base and provide a report that includes quality scores for the following:
The Coding Network is a leader in medical coding services. Their custom Python application needed work, and due to the critical nature of medical records, the work needed to be performed by an expert medical software consultancy who would take care to not introduce new bugs or regressions. So they partnered with FullStack Labs, and over the course of a few years, we've taken over all development and maintenance responsibilities, allowing TCN to focus on their core competencies...medical billing.
“It’s not easy to get 5 stars from me but you guys have been great! You show up on time, you finish within the schedule. We’re doing accounting and financial systems which means that you have to learn the business side of it. It’s not only software, you have to understand the workflow. Our experience has been amazing.“
An all inclusive, opinionated framework, we choose django for robust applications that require specific feature sets.
The experience I've had with other firms is in direct contrast to what FullStack did. I'm comparing them with two other firms I worked with in the past. They care a lot about what their clients are doing. They bring their ideas and concepts to the table. I felt like they were on my team. They added a lot of value in terms of ideas and continue to do so. No matter who's working on the project you feel like they care about the work that's being produced.
FullStack Labs' managers have been engaged throughout. The whole project management staffing, matching team to task has been fantastic. All their staff is very committed. I'm very aware of how much bureaucracy there is in the tech world, and we've gotten nothing but solutions. I am totally happy with their approach to everything, their integrity, honesty, the whole thing. It's great.
We were very happy with the way the whole process was facilitated. We started talking to FullStack Labs three months before we signed any contract with them. We met with them in person several times. We wanted to find out what their philosophy is. Both Brian and David are fathers with young children, so they understand the importance of the work we are doing. That shows through in their work. It was obvious they cared deeply.
We will work with you to understand your technical needs, team dynamics, and goals.
We’ll send you FullStack Python developers that match your technical requirements, with links to their FullStack profile page which outlines their work experience and technical abilities, as well as their FullStack technical summary page, which includes a 60 minute video of the developer completing FullStack’s coding challenge, and a plethora of other technical information from their interview with us.
Start the engagement. Work with your new Python developers for a trial period, ensuring they're the right fit.
At FullStack Labs, we’re all about excellence in software development. That’s why we hire the best Python Developers in the US and Latin America and pair you up with seasoned experts that fill your talent gaps and deliver critical value to your project.
From a single Python engineer to a fully-featured software development team, we provide you with solutions that allow you to scale up and down as needed. All of our contracts are month-to-month and can be canceled with 30-days notice.
Each day you'll receive a detailed report that shows all hours billed the previous day with a description of what was completed, as well as month-to-date and year-to-date totals. This applies to all projects, regardless of size or complexity.
Our detailed management and billing process is focused on transparency, and we use it to measure the efficiency of our developers. This way, you only pay for the hours we work—no weekly or monthly block billing.
Most of our engineers onboard to client projects in less than 2 weeks and immediately ramp up development and project contributions. We handle all of the onboarding overhead so that you and your team can focus on building great software.
Our talent is distributed across more than 17 countries in Central and South America. We’re able to reach a large pool of talent, always making sure to assign the region’s top engineers to your project.
Have a legacy Python app? We’re here to help. From debugging and maintenance to feature development and DevOps, we'll tailor a development plan to meet your needs.
Need to add a Python developer to your existing team? We'll seamlessly integrate as many Python developers as needed, to help you go faster and level up your team's skills.
We’d love to learn more about your project.
Engagements start at $75,000.
At FullStack Labs, we hire the best Python developers, engineers, programmers, coders, and architects in the US and Latin America. Uber, Siemens, and hundreds of other companies have chosen us for their mission-critical software development projects.
Since many of our clients like to interview our developers before onboarding them to their projects, we’ve put together a few Essential Python Interview Questions you can use to screen the candidates in your shortlist.
Q.1a - What will be the output of the code below? Explain your answer.
The output of the above code will be:
Many will mistakenly expect list1 to be equal to  and list3 to be equal to ['a'], thinking that the list argument will be set to its default value of  each time extendList is called. However, this is not the case. Instead, the value of list1 changes from  to [10, ‘a’] as soon as we call extendList(‘a’) and define list3. This is how that looks in code:
But why does this happen? Well, that’s because the default list in the extendList function is created only once—which happens when the function is defined. After that, every resulting list from a function call will be used subsequently whenever extendList is invoked without a specified list argument. In other words, the expressions in default arguments are calculated when the function is defined, and not when it’s called.
Therefore, list1 and list3 are operating on the same default list, whereas list2 is operating on the list defined by the second argument, bypassing its own empty list as the value for the list parameter. The same would apply in case a list4 didn’t specify a list argument:
Q.1b - How would you modify the definition of extendList to produce the presumably desired behavior?
The definition of the extendList function can be easily modified to achieve the commonly mistaken expectation of this script. The trick is to always create a new list when no list argument is specified:
With this revised implementation, the output would be:
Q.2a - What will be the output of the code below? Explain your answer.
The output of the above code is [6, 6, 6, 6] and not [0, 2, 4, 6].
This is because Python’s closures are late binding, which means that the values of variables used in closures are looked up at the time the inner function is called. So, as a result, when any of the functions returned by multipliers() are called, the value of i is looked up in the surrounding scope at that time. By then, regardless of which of the returned functions is called, the for loop has completed and i is left with its final value of 3. Therefore, every returned function multiplies the value it is passed by 3, so since a value of 2 is passed in the above code, they all return a value of 6 (i.e., 3 x 2).
Incidentally, as pointed out in The Hitchhiker’s Guide to Python, there is a somewhat widespread misconception that this has something to do with lambdas, which is not the case. Functions created with a lambda expression are in no way special and exhibit the same behavior as any ordinary function.
Q.2b - How would you modify the definition of multipliers to produce the presumably desired behavior?
Below are a few examples of ways to circumvent this issue.
One solution would be to use a Python generator as follows:
Another solution is to create a closure that binds immediately to its arguments by using a default argument. For example:
Or alternatively, you can use the functools.partial function:
Finally, the easiest fix may be to simply replace the return value’s  with ():
Q.3 - What will be the output of the code below? Explain your answer
The output of the above code will be:
What confuses or surprises many about this is that the last line of output is 3 2 3 rather than 3 2 1. Why does changing the value of Parent.x also change the value of Child2.x, but at the same time not change the value of Child1.x?
The key to the answer is that, in Python, class variables are internally handled as dictionaries. If a variable name is not found in the dictionary of the current class, the class hierarchy (i.e., its parent classes) are searched until the referenced variable name is found (if the referenced variable name is not found in the class itself or anywhere in its hierarchy, an AttributeError occurs).
Therefore, setting x = 1 in the Parent class makes the class variable x (with a value of 1) referenceable in that class and any of its children. That’s why the first print statement outputs 1 1 1.
Subsequently, if any of its child classes overrides that value (for example, when we execute the statement Child1.x = 2), then the value is changed in that child only. That’s why the second print statement outputs 1 2 1.
Finally, if the value is then changed in the Parent (for example, when we execute the statement Parent.x = 3), that change is reflected also by any children that have not yet overridden the value (which in this case would be Child2). That’s why the third print statement outputs 3 2 3.
Q.4a - What will be the output of the code below? Explain your answer.
In Python 2, the output of the above code will be:
By default, Python 2 automatically performs integer arithmetic if both operands are integers. As a result, 5/2 yields 2, while 5./2 yields 2.5. Note that you can override this behavior in Python 2 by adding the following import:
Also note that the “double-slash” (//) operator will always perform integer division, regardless of the operand types. That’s why 5.0//2.0 yields 2.0 even in Python 2.
Q.4b - Also, how would the answer differ in Python 3 (assuming, of course, that the above print statements were converted to Python 3 syntax)?
In Python 3, division behaves differently than in Python 2; i.e., it does not perform integer arithmetic if both operands are integers. Therefore, in Python 3, the output will be as follows:
Q.5 - What will be the output of the code below?
The above code will output , and will not result in an IndexError.
As one would expect, attempting to access a member of a list using an index that exceeds the number of members (e.g., attempting to access list in the list above) results in an IndexError. However, attempting to access a slice of a list at a starting index that exceeds the number of members in the list will not result in an IndexError and will simply return an empty list.
What makes this particularly tricky is that it can lead to bugs that are really hard to track down since no error is raised at runtime.
Q.6 - Consider the following code snippet, what will be the output of lines 2, 4, 6, and 8? Explain your answer.
The output will be as follows:
The first line of output is presumably intuitive and easy to understand; i.e., list = [ [ ] ] * 5 simply creates a list of 5 lists.
However, the key thing to understand here is that the statement list = [ [ ] ] * 5 does not create a list containing 5 distinct lists; rather, it creates a list of 5 references to the same list. With this understanding, we can better understand the rest of the output.
list.append(10) appends 10 to the first list. But since all 5 lists refer to the same list, the output is: [, , , , ].
Similarly, list.append(20) appends 20 to the second list. But again, since all 5 lists refer to the same list, the output is now: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]].
In contrast, list.append(30) is appending an entirely new element to the “outer” list, which therefore yields the output: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].
Q.7 - What is the solution to the following list comprehension problem?
Given a list of N numbers, use a single list comprehension to produce a new list that only contains values that comply with the following requirements:
For example, if list contains a value that is even, that value should be included in the new list, since it is also at an even index (i.e., 2) in the original list. However, if list contains an even number, that number should not be included in the new list since it is at an odd index (i.e., 3) in the original list
A simple solution to this problem would be as follows:
For example, given the following list
the list comprehension [x for x in list[::2] if x%2 == 0] will evaluate to:
The expression works by first taking the numbers that are at the even indices, and then filtering out all the odd numbers.
Q.8 - Will this code work? Why or why not?
Given the following subclass of dictionary:
will the code below work? Why or why not?
Actually, the code shown will work with the standard dictionary object in Python 2 or 3—that is normal behavior. Subclassing dict is unnecessary. However, the subclass still won’t work with the code shown because __missing__ returns a value but does not change the dict itself:
So it will “work,” in the sense that it won’t produce any error, but doesn’t do what it seems to be intended to do.
Here is a __missing__-based method that will update the dictionary, as well as return a value:
Also, note that a defaultdict object has been available in the standard library since version 2.5 of Python.
Q.9 -How would you unit-test the following code?
A good answer would suggest a specific async mock library and async test case approach, including an ephemeral event loop that’s guaranteed to terminate (i.e. with a max number of steps before timeout.)
A great answer would point out that synchronization problems are fundamentally the same in synchronous and asynchronous code, the difference being preemption granularity.
And an even better answer would take into account that the above code only has one flow (easy) compared to some other code where flows are mixed (e.g. merging two streams into one, sorting, etc). For example, consider the following upgrade to the given code:
Here, any of the async statements could have a side-effect of changing the global keep_running.
Q.10 - How do you list the functions in a module?
Use the dir() method to list the functions in a module.
Q.11 - Can you write a function that solves the following problem?
Your function must print the least integer that is not present in a given list and cannot be represented by the summation of the sub-elements of the list. For example, in the list a = [1,2,5,7] the least integer not represented by the list or a slice of the list is 4, and if a = [1,2,2,5,7] then the least non-representable integer is 18.