Static variables [was Re: syntax difference]

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Jun 25 20:10:07 EDT 2018


On Mon, 25 Jun 2018 18:22:56 +0000, Grant Edwards wrote:

> On 2018-06-24, Steven D'Aprano <steven.d'aprano at 1> wrote:
> 
>> Building functions is cheap. Cheap is not free.
>>
>> Inner functions that aren't exposed to the outside cannot be tested in
>> isolation, you can't access them through help() interactively. Given
>> the choice between:
> 
> [...]
> 
>> so not expensive, but not free either. If using an inner function has
>> no advantages to you, why pay that tiny cost for no benefit?
> 
> The benefit of an inner function is that it makes it perfectly clear to
> the reader that that function is not used outside the function where it
> is defined.  It also makes it more difficult for other fuctions to muck
> things up by changing the binding of a global name.

You say "muck things up", I say "use mocks for testing".

You're right, I shouldn't have said *no* advantages, I should have said 
"few". (Although I did use the proviso, no advantages to *you* -- this is 
a personal trade-off each programmer must make.)

Inner functions are especially useful in languages like Pascal with 
compile-time correctness tests (a.k.a. static type checking). Python 
doesn't have those, so we rely far more on unit tests. My personal trade-
off is that with no way to test inner functions, I have to assume that 
they're buggy.

(Aside from those which are simple enough to be obviously correct, as 
opposed to those that have no obvious bugs.)

Inner functions are particularly insidious because they *look* like you 
can doctest them, but you can't. I once got badly bitten by a program I 
wrote which used doctests extensively. Every doctest passed, or at least 
so I thought, and yet the program was *badly* incorrect when I ran it.

Eventually I worked out that because the doctests were in inner 
functions, they weren't being run. My TDD was in vain -- I thought my 
tests were passing, but they weren't being run at all, and the inner 
functions were riddled with bugs.

So I've always been rather wary of using inner functions since then.


> IOW, you use a local function instead of a global one for the exact same
> reasons you use local "variables" instead of global ones.

Well, I dunno... functions aren't quite like variables. Variables are 
pretty boring things, they just take a value, whereas functions can be 
quite complex entities that *do stuff*. Functions ought to be tested.

You're also likely to have far fewer functions than variables, and far 
fewer likely name clashes. You might have a dozen variables called 
"total" but only one function called "calculate_total". It would be 
terribly hard to write a program with only global variables, but it is 
rather easy to write one with only global functions, and some languages 
don't offer the ability to next functions at all.


> In Python, functions are first class objects.  Binding a name to a
> function is no different than binding it to an integer, list, string, or
> dict.  Don't the global vs. local cost vs. benefit calculations apply
> equally well to function objects as they do to those other sorts of
> objects?

I've never measured it, but I would expect that, cheap as it is, 
constructing a new function each time you need to call it would be more 
expensive than looking up a pre-existing global function.


-- 
Steven D'Aprano
"Ever since I learned about confirmation bias, I've been seeing
it everywhere." -- Jon Ronson




More information about the Python-list mailing list