How to extend/overload range() function from Python 2.7 to accept floats?
<p>Our core application changed from Python 2.6 to Python 2.7 maybe to Python 3 in later release.</p>

<p>Range function from python is changed (quote from the Python 2.7 changelog).</p>

<blockquote>
  <p>The <code>range()</code> function processes its arguments more consistently; it
  will now call <code>__int__()</code> on non-float.</p>
</blockquote>

<p>We allow users to add expressions / Python code based on results we process further.</p>

<p>Now how to change <code>range</code> function? Some of them are using <code>float</code> argument that are failing now in Python 2.7.</p>

<p>As code is written by users we cannot change in Python code/expression. There are 1000s of files. Some users may have their own files.</p>

<ol>
<li><p>Is there is a way to extend the <code>range()</code> function from Python, such that it will take float arguments?</p></li>
<li><p>Another alternative is to parse python code and change <code>float</code> to <code>int</code>. It is very time consuming as it requires lot of sting manipulation and some <code>range</code> calls have formulas as parameter.</p></li>
</ol>

<p>Our application build in C++, and we evaluate python expression using C++ python APIS</p>

<p>The change is not that calling <code>__int__</code> on non-float. The change affecting you is that float arguments are not accepted any more in Python 2.7:</p>

<pre><code>Python 2.6.9 (default, Sep 15 2015, 14:14:54) 
[GCC 5.2.1 20150911] on linux2
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; range(10.0)
__main__:1: DeprecationWarning: integer argument expected, got float
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
</code></pre>

<p>See the <code>DeprecationWarning</code> - all this time your code has emitted warnings but you chose to ignore them. In Python 2.7:</p>

<pre><code>Python 2.7.12 (default, Jul  1 2016, 15:12:24) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; range(10.0)
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
TypeError: range() integer end argument expected, got float.
</code></pre>

<p>The solution is to wrap the <code>range()</code> into a new function:</p>

<pre><code>def py26_range(*args):
    args = [int(i) if isinstance(i, float) else i for i in args]
    return range(*args)
</code></pre>

<p>This function coerces floats into ints retaining the Python 2.6 behaviour. You then need to replace all usages of <code>range</code> with <code>py26_range</code> in those parts of code where the argument might be a float.</p>

<hr>

<p>If you're desperate enough, you can install this version of <code>range</code> into <code>__builtin__</code>:</p>

<pre><code>from functools import wraps
import __builtin__

@wraps(range)
def py26_range(*args):
    args = [int(i) if isinstance(i, float) else i for i in args]
    return range(*args)    

__builtin__.range = py26_range
</code></pre>

<p>Execute this before the other modules are <em>even imported</em> and it should work as before.</p>

python python-2.7 python-2.6