<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 16, 2018 at 10:33 AM, Jonathan Fine <span dir="ltr"><<a href="mailto:jfine2358@gmail.com" target="_blank">jfine2358@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">>> there<br>
>> are times where I have really wanted to access the caller's environment,<br>
>> not the environment where my function was defined.<br>
<br>
> what am I missing? can't you get that by passing locals() in to a function?<br>
<br>
</span>I think this will fail when values are changed. According to<br>
<a href="https://docs.python.org/3/library/functions.html#locals" rel="noreferrer" target="_blank">https://docs.python.org/3/<wbr>library/functions.html#locals</a><br>
> The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.<br></blockquote><div><br></div><div>and:<br>"""<br>locals()<br><br>Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks.<br><br>"""</div><div><br></div><div>it a dictionary *representing* the current local symbol table, so not the actual symbol table -- which surprised me, I thought that is was -- and sometimes it appears to be -- see later example:</div><div> </div><div>> To finish, here's an interactive example of changing the value of locals().</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
>>> def f(a=1): loc = locals(); yield loc; yield a<br>
>>> it = f()<br>
>>> ctx = next(it)<br>
>>> ctx<br>
{'a': 1} ## This surprised me.<br></blockquote><div><br></div><div>me too I would have thought "loc" would be in there.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">>>> def f(a=1): loc = locals(); yield locals(); yield a<br>
>>> it = f()<br>
>>> ctx = next(it)<br>
>>> ctx<br>
{'a': 1, 'loc': {...}}<br></blockquote><div><br></div><div>now "loc is there"</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
>>> ctx['a'] = 3<br>
>>> ctx['loc']['a'] = 5<br>
>>> next(it) ## Is it 1 or 3 or 5?<br>
1 ## The value of 'a' hasn't changed.</blockquote><div><br></div><div>hmm -- made me think that generators are doing something different here -- and indeed they are. If you use regular functions:</div><div><br></div><font face="monospace, monospace">In [30]: def local_modifying(loc):<br> ...: """<br> ...: adds a "fred" key to the dict passed in<br> ...: """<br> ...: print("locals passed in:", loc)<br> ...: loc['fred'] = 5<br> ...: print("locals after adding", loc)<br> ...: <br><br>In [31]: def test_locals():<br> ...: """<br> ...: a simple local namespace to use<br> ...: """<br> ...: a = 1<br> ...: b = 2<br> ...: local_modifying(locals())<br> ...: # does "fred" exist?<br> ...: print(locals())<br> ...: # and we can access it the usual way<br> ...: print("fred:", fred)<br> ...: <br>In [32]: test_locals()<br>locals passed in: {'b': 2, 'a': 1}<br>locals after adding {'b': 2, 'a': 1, 'fred': 5}<br>{'b': 2, 'a': 1, 'fred': 5}<br>fred: 5</font><div><br></div><div>It seems you CAN modify the locals dict passed in, and the change will show up in the enclosing scope.</div><div><br></div><div>But it sounds like that is not guaranteed by the language.</div><div><br></div><div>-CHB</div><div><br></div></div><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><br>Christopher Barker, Ph.D.<br>Oceanographer<br><br>Emergency Response Division<br>NOAA/NOS/OR&R (206) 526-6959 voice<br>7600 Sand Point Way NE (206) 526-6329 fax<br>Seattle, WA 98115 (206) 526-6317 main reception<br><br><a href="mailto:Chris.Barker@noaa.gov" target="_blank">Chris.Barker@noaa.gov</a></div>
</div></div>