DEV Community

Cover image for DeepCode’s Top Findings#7: Python Use Real Floor Division
cu_0xff 🇪🇺 for DeepCode.AI

Posted on • Originally published at Medium

DeepCode’s Top Findings#7: Python Use Real Floor Division

Language: Python
Defect: DivisionRounding
Diagnose: Use // instead of / to make sure the value is rounded to an integer and not fractional. %function% expects an int as its first argument.

This example is sponsored by tensorflow / models and you can follow along by loading it into your dashboard on deepcode.ai

Screenshot

I was fascinated by this as it shows a difference between Python 2.7 and 3. The code snippet below shows the interesting parts.

... def take_action(self, current_node_ids, action, step_number): ... goal_number = step_number / self.task_params.num_steps ... if n == self.episode.goal_node_ids[goal_number][i]: ... 
Enter fullscreen mode Exit fullscreen mode

step_number and self.task_params.num_steps are both integers. In Python 2.7, the division operator / works as a floor division. But dividing integers will always result in an integer.

Python 2.7.16 (default, Jul 13 2019, 16:01:51) [GCC 8.3.0] on linux > 3/4 0 > 9/10 0 
Enter fullscreen mode Exit fullscreen mode

This is no longer true with Python 3.

Python 3.7.4 (default, Jul 9 2019, 00:06:43) [GCC 6.3.0 20170516] on linux > 3/4 0.75 > 9/10 0.9 > 4/2 2.0 
Enter fullscreen mode Exit fullscreen mode

See the difference? In Python 3, the division behaves differently, so you need to be careful. A division between two integers results in a floating-point number, even if there is no remainder.
What DeepCode did under the hood was a type analysis and it inferred that goal_number is a floating-point number. It traced goal_number to its definition and found it to be a result of a division of two integers. But it is later used as the parameter for an index operator which needs to be an integer. If the program calls the index-operator with float, it results in TypeError. DeepCode learned from scanning thousands of open source repos that typically this should have been a real floor division // instead of a division /. And it happens quite frequently when porting code from Python 2.7 to Python 3.

Python 3.7.4 (default, Jul 9 2019, 00:06:43) [GCC 6.3.0 20170516] on linux > table = [1,2,3,4,5,6,7,8,9,10] > a = 30 > b = 10 > table[a/b] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: list indices must be integers or slices, not float > table[a//b] 4 
Enter fullscreen mode Exit fullscreen mode

To "simulate" the Python 2.7 behavior, you can use the floor division operator //.

Python 3.7.4 (default, Jul 9 2019, 00:06:43) [GCC 6.3.0 20170516] on linux > 3//4 0 > 9//10 0 
Enter fullscreen mode Exit fullscreen mode

Not sure if this still is of interest but in Python 2.7 // works on integers just as expected so it is safe to use.

Top comments (0)