Question about math.pi is mutable
BartC
bc at freeuk.com
Mon Nov 9 07:22:22 EST 2015
On 09/11/2015 02:23, Steven D'Aprano wrote:
> On Mon, 9 Nov 2015 09:35 am, BartC wrote:
>> import m
>> a=10
>> b=20
>> c=30
>> m.f()
>>
>> The set of global names the compiler knows will be ("m","a","b","c").
>
> Wrong. Up to the line "c=30", the set of names the compiler can infer are m,
> a, b and c. Once the line "m.f()" executes, *all bets are off*. The
> compiler can no longer infer *anything* about those names. In principle,
> m.f may have reached into the globals and deleted *any* of the names,
> including itself.
>
>
>> I don't believe code can remove these names (that would cause problems).
>
> Of course names can be removed. There's even a built-in statement to do
> so: "del".
I tried this code:
a=10
print (a)
del a
#print (a)
a=20
print (a)
That sort of confirms what you are saying: that names don't even come
into existence until the first time they are encountered. They don't
just contain None, or some other value which means the name itself
exists, but it hasn't been initialised to anything. And that del removes
the name completely from the set that are known.
That makes Python unlike any other language I've used.
On the other hand, if I put the above code into a function and then call
the function, attempting to print a just after it's been deleted results in:
UnboundLocalError: local variable 'a' referenced before assignment
So while local names can presumably be manipulated just like globals,
that doesn't stop being implemented via a fixed slot in a table.
>> Therefore these names could be referred to by index.
>
> Perhaps. But that adds significant complexity to the compiler,
It would mean that each name needs a flag indicating whether or not it
has yet been brought into existence by an assignment in the program, or
has been banished by the use of del.
> and the
> performance benefits *in practice* may not be as good as you imagine. After
> all, there is usually far more to real programs than just getting and
> setting names.
Any programs will consist largely of pushing names and constants (LOAD
ops), performing some operations on them, and then sometimes popping
values (STORE ops).
If the names represent complex data, then doing the work on the data
will dominate the timings. But often it's the 'little' variables that
hold indices, counts, flags etc that are being frequently loaded and stored.
> def unopt():
> from math import * # Defeats the local variable optimization.
> x = sin; x = cos; x = tan; x = exp; x = pi
> x = e; x = trunc; x = log; x = hypot; x = sqrt
> return
>
> def opt():
> from math import sin, cos, tan, exp, pi, e, trunc, log, hypot, sqrt
> x = sin; x = cos; x = tan; x = exp; x = pi
> x = e; x = trunc; x = log; x = hypot; x = sqrt
> return
> When I run this code, I get
>
> 16.5607659817 seconds for unopt, and 3.58955097198 seconds for opt. That's a
> significant difference.
The optimisation means the code can use LOAD_FAST instead of LOAD_NAME.
It still uses STORE_FAST instead of STORE_NAME, so perhaps the
difference could be even more if the unoptimised version had to use
STORE_NAME.
--
Bartc
More information about the Python-list
mailing list