Ways to make a free variable local to a function?

Terry Reedy tjreedy at udel.edu
Mon Mar 5 08:52:40 EST 2018


On 3/5/2018 7:12 AM, Kirill Balunov wrote:
> Hi,
> 
> At the moment, in order to slightly speed up the function in Python, free
> variables are passed as local variables to the function, thereby getting
> rid of extra look ups. For example, for the following function, I
> especially do not use list comprehension) and therefore maybe it's not the
> best example:
> 
>      def func(numb):
>          res = []
>          for i in range(numb):
>              res.append(int(i) + float(i))
>          return res
> 
> You can get rid of additional look ups, in the following ways:
> 
> 
> # 1. By passing through local variable's default values
> 
>      def func_local_1(numb, _int = int, _float = float, _range = range):

You are not required to mangle the names.

def func_local_1(numb, int = int, float = float, range = range):
...

>      res = []
>      for i in _range(numb):
>          res.append(_int(i) + _float(i))
>      return res
> 
> 
> # 2. Through importing them into the function scope
> 
>      def func_local_2(numb):
>          from builtins import int, float, range
>          res = []
>          for i in range(numb):
>              res.append(int(i) + float(i))
>          return res
> 
> 
> # 3. With the help of various types of closures, version 1
> 
>      def func_closure_1(numb):
>          _int = int
>          _float = float
>          _range = range
>          def inner(numb):
>              res = []
>              for i in _range(numb):
>                  res.append(_int(i) + _float(i))
>              return res
>          return inner(numb)
> 
> 
> # 4. With the help of various types of closures, version 2
> 
>      def func_closure_2(numb):
>          from builtins import int, float, range
>          def inner(numb):
>              res = []
>              for i in range(numb):
>                  res.append(int(i) + float(i))
>              return res
>          return inner(numb)
> 
> Option 1 allows you to achieve the maximum result for both small and a
> large `numb` values. Option 2 yields a significant overhead, when it is
> required to call function many times with a small number of iterations. For
> option 3 and 4, notes are the same, but since they are implemented through
> closures they give additional small overhead. In case of big `numb` (many
> iterations, many look ups) these options give a gain of ~10%.
> 
> Option 1 and 3 I do not like because:
>   - syntax highlighting stops working

Only because you unnecessarily mangle the names.

>   - the signature function is greatly distorted
>   - additional typing (especially with type annotations)
> 
> I like options 2 and 4, but they yield a significant overhead, for a small
> number of iterations.
> 
> Actually, I have the following question:
> 
> 1. Is there any other way to make the variable local to the function?
>       a. When you compile (define) a function...
>       b. Inject into an already existing function through decorator...(is it
> possible?)
> 
> p.s.:
> 
> I had the following idea, maybe it was already discussed, the possibility
> of setting _static_ variables for functions, with the following syntax:
> 
>      def func(numb):
>          static int, float, range
>          res = []
>          for i in range(numb):
>              res.append(int(i) + float(i))
>          return res
> 
> Where identifiers for `static` should correspond to free variables for a
> function, they must be defined at compile time (like for default arguments)
> and can not be changed inside the function scope.
> 
> With kind regards,
> -gdg
> 


-- 
Terry Jan Reedy




More information about the Python-list mailing list