Putting a function to a local namespace to speeding up access taking descriptors into account
Question: I use `numpy.random.normal` function in a **tough** loop in a class.

    
    
    class MyClass(MyBaseClass):   
        def run(self):
            while True:
                ...
                self.L.append(numpy.random.normal(0,1))
    

I know that it's pretty slow in Python to use multiple lookups. In
`numpy.random.normal` there are 3 lookups: first `numpy` is looked up, then
`random`, and then `normal`.

So I decided to address this problem by assigning `numpy.random.normal` to a
local variable `_normal`.

Here we go:

    
    
    class MyClass(MyBaseClass):
        _normal = numpy.random.normal
        def run(self):
            while True:
                ...
                self.L.append(MyClass._normal(0,1))
    

What I'm really concerned about is descriptors. When a variable in a class in
accessed, all the bases classes are looked up for the **data descriptor** with
the same name. It's described
[here](http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#attribute-
search-summary):

> Check `objectname.__class__.__dict__`for attrname. If it exists and is a
> data-descriptor, return the descriptor result. Search all bases of
> `objectname.__class__` for the same case.

So, I guess, if I put `_normal` in the local space as I did above, it will
case looking up all bases classes for the data descriptor. And I wary of it
becoming a source of a slowdown.

Are my concerns justified?

Should I worry about the time it takes to look up for the descriptors in base
classes?

And is there a better way to speed up access to a function located deep into a
module when it's used in a class?

* * *

There was a discussion in the comments to the answers.

I decided to give some additional details of implementation that appeared to
be important (for my particular case).

Actually, the code is closer to this (it's very very simplified):

    
    
    class MyClass(MyBaseClass):
    
        def __iter__(self):
            return self
    
        def next(self):
            self.L.append(numpy.random.normal(0,1))   
    
        def run(self):
            while True:
                self.next()
    


Answer: If you must do something like this (is function lookup actually the dominant
cost? Random number generation is not cheap) you should realize that one
global + one attr lookup (`MyClass._normal`) is not that much cheaper than one
global + three attr lookups (`numpy.random.normal`). What you really want is
to get _zero_ global or attr lookups inside the loop, which you can only do by
defining `_normal` _inside the function_. If you're really desperate to shave
cycles you should also prebind the list append call:

    
    
    class MyClass(MyBaseClass):
        def run(self):
            _normal = numpy.random.normal
            _Lappend = self.L.append
            while True:
                ...
                _Lappend(_normal(0,1))
    

Contrast disassembly output (just for the `append` statement):

    
    
      LOAD_FAST                0 (self)
      LOAD_ATTR                1 (L)
      LOAD_ATTR                2 (append)
      LOAD_GLOBAL              3 (numpy)
      LOAD_ATTR                4 (random)
      LOAD_ATTR                5 (normal)
      LOAD_CONST               1 (0)
      LOAD_CONST               2 (1)
      CALL_FUNCTION            2
      CALL_FUNCTION            1
      POP_TOP             
    

vs

    
    
      LOAD_FAST                2 (_Lappend)
      LOAD_FAST                1 (_normal)
      LOAD_CONST               1 (0)
      LOAD_CONST               2 (1)
      CALL_FUNCTION            2
      CALL_FUNCTION            1
    

What would be even better is to vectorize -- generate many random normal
deviates from and append them to the list in one go -- you can do that with
the `size` argument to `numpy.random.normal`.

