What happened when invoking locals() in python3? - python-3.7

I'm using Python3.7.2
The code which makes me confused looks like this:
def foo(cond):
if cond:
z = 1
return z
else:
loc = locals()
x = 1
locals()['y'] = 2
exec("z = x + y")
print(loc)
print(locals())
foo(False)
Here is the result it prints:
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2, 'z': 3}
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2}
The exec function changes the local namespace, but when I execute locals(), variable z disappeared.
However, if I change the code like this:
def foo(cond):
if cond:
return 1
else:
loc = locals()
x = 1
locals()['y'] = 2
exec("z = x + y")
print(loc)
print(locals())
foo(False)
The result will be:
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2, 'z': 3}
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2, 'z': 3}
I'm really confused. :(

In short: the dictionary returned by locals() is only a copy of the true local variables—which are stored in an array, not in a dictionary. You can manipulate the locals() dictionary, add or remove entries at will. Python does not care since that is merely a copy of the local variables it works with. However, each time you call locals(), Python copies the current values of all local variables into the dictionary, replacing anything else you or exec() put in before. So, if z is a proper local variable (as in the first, but not second version of your code), locals() will restore its current value, which happens to be "not set" or "undefined".
Indeed, conceptually Python stores local variables in a dictionary, which can be retrieved through the function locals(). However, internally, it really is two arrays. The names of the locals are an attribute of the code itself and therefore stored in the code object as code.co_varnames. Their values, however, are stored in the frame as fast (which is inaccessible from Python code). You can find more on co_varnames etc. in inspect and dis modules, respectively.
The built-in function locals() actually calls a method fastToLocals() on the current frame object. If we were to write the frame with its fastToLocals method in Python, it might look like this (I am leaving out a lot of details here):
class frame:
def __init__(self, code):
self.__locals_dict = None
self.f_code = code
self.__fast = [0] * len(code.co_varnames)
def fastToLocals(self):
if self.__locals_dict is None:
self.__locals_dict = {}
for (key, value) in zip(self.f_code.co_varnames, self.__fast):
if value is not null: # Remember: it's actually C-code
self.__locals_dict[key] = value
else:
del self.__locals_dict[key] # <- Here's the magic
return self.__locals_dict
def locals():
frame = sys._getframe(1)
frame.fastToLocals()
In plain English: the dictionary you get when calling locals() is cached in the current frame. Calling locals() repeatedly will give you the same dictionary (__locals_dict in the code above). However, each time, you call locals(), the frame will update the entries in this dictionary with the current values that local variables have at that time. As noted here, when a local variable is not set, the entry in the __locals_dict is deleted. And that's what it is all about.
In your first version of the code, the third line says z = 1, which makes z a local variable. In the else branch, however, that local variable z is not set (i.e. would raise a UnboundLocalError) and is therefore removed from the __locals_dict. In the second version of your code, there is no assignment to z, so it is not a local variable and the locals() function does not care about it.
The set of local variables is actually fixed by the compiler. This means that you cannot add or remove local variables at runtime. This is a problem for exec(), as you are clearly using exec() here to define a local variable z. Python's way out is to say that exec() stores z as a local variable in the _locals_dict dictionary, although it cannot put it into the arrays behind this dictionary.
Conclusion: The values of local variables are actually stored in an array, not in the dictionary returned by locals(). When calling locals(), the dictionary is updated with the true current values taken from the dictionary. exec(), on the other hand, can only store its local variables in the dictionary, not in the array. If z is a proper local variable, it will be overwritten by a call to locals() with its current value (which is "does not exist"). If z is not a proper local variable, it will stay in the dictionary untouched.
Python's specifications say that any variable that you assign to inside a function is a local variable. You can change this default through the use of global or nonlocal, of course. But as soon as you write z = ..., z becomes a local variable. If, on the other hand, you only have x = z in your code, the compiler assumes that z is rather a global variable. That's why the line z = 1 makes all the difference: it marks z as a local variable that receives its place in the fast array.
Concerning exec(): in general, there is no way the compiler could really know what code exec() is going to execute (in your case with a string literal it could, but since this is a are rare and uninteresting case, it never tries, anyway). The compiler can therefore not know what local (or global) variables the code in exec() might access, and cannot include that in its calculation of how large the array of local variables should be.
By the way: that local variables are managed in arrays instead of proper dictionaries is the reason why there might be raised an UnboundLocalError instead of an NameError. In case of local variables, the Python interpreter actually recognises the name and knows exactly where its value is to be found (inside the fast array mentioned above). But if that entry is null, it cannot return something meaningful and therefore raises the UnboundLocalError. For global names, however, Python goes really searched for a variable with the given name in the globals and built-in dictionaries. In that case, a variable of the requested name might truly not exist.

Compare your code with the following:
def foo(cond):
if cond:
return 1
else:
loc = locals().copy()
# ——————————————^
x = 1
locals()['y'] = 2
exec("z = x + y")
print(loc)
print(locals())
foo(False)
It produces
{'cond': False}
{'cond': False, 'loc': {'cond': False}, 'x': 1, 'y': 2, 'z': 3}
as you might expect. The reason is that locals() is a reference, not a value.

Related

What is the difference between constant variable which is type of list and constant list

This is a basic question, but can't find elsewhere.
In dart we can declare a constant variable as
const foo = [1,2,3];
or
var foo = const [1,2,3];
Is there any performance related change if we use either any one.
When you do
const foo = [1, 2, 3];
It means foo will always be equal to [1, 2, 3] independently of the previously executed code and won't change its value later.
When you do
var foo = const [1, 2, 3];
It means that you are declaring a variable foo (and not a constant) which equals at this moment to the constant [1, 2, 3] (it is not dependant on the previously executed code). But the value foo can change and you could do later:
foo = const [1, 2];
which will be legit since foo is a variable. You couldn't do that with foo as a constant (since it is constant)
Therefore, it is better when you can to write
const foo = [1, 2, 3];
because it indicates to the compiler that foo will never change its value.
If constants are called literals and literals are data represented directly in the code, how can constants be considered as literals?
The article from which you drew the quote is defining the word "constant" to be a synonym of "literal". The latter is the C++ standard's term for what it is describing. The former is what the C standard uses for the same concept.
I mean variables preceded with the const keyword are constants, but they are not literals, so how can you say that constants are literals?
And there you are providing an alternative definition for the term "constant", which, you are right, is inconsistent with the other. That's all. TP is using a different definition of the term than the one you are used to.
In truth, although the noun usage of "constant" appears in a couple of places in the C++ standard outside the defined term "null pointer constant", apparently with the meaning you propose here, I do not find an actual definition of that term, and especially not one matching yours. In truth, your definition is less plausible than TutorialPoint's, because an expression having const-qualified type can nevertheless designate an object that is modifiable (via a different expression).
const int MEANING = 42;
the value MEANING is a constant, 42 is a literal. There is no real relationship between the two terms, as can be seen here:
int n = 42;
where n is not a constant, but 42 is still a literal.
The major difference is that a constant may have an address in memory (if you write some code that needs such an address), whereas a literal never has an address.

Implementing the map function for a Pony array

I have been playing with Pony arrays to understand Pony better, and wanted to write the map function for any arrays.
I am talking about something like the standard map function most languages have nowadays for converting elements of collections, as in Clojure:
(map #(+ 1 %) [1 2 3]) ; => [2 3 4]
But I want it to actually modify the given array, not return a new one.
My current attempt so far runs into many errors due to capabilities:
// array is "iso" so I can give it to another actor and change it
let my_array: Array[U64] iso = [1; 2; 3; 4]
// other actor tries to recover arrays as "box" just to call pairs() on it
let a = recover box my_array end // ERROR: can't recover to this capability
for (i, item) in a.pairs() do
// TODO set item at i to some other mapped value
try my_array.update(i, fun(item))? end
end
Anyone knows how this can be done
Alright, took me a while, but I was able to get things working.
Here's my basic understanding of what's going on (please correct me if I'm wrong)!
The first step was to understand that we need to use aliases to change the capabilities of a variable in Pony.
So, in order to make an iso variable useable as a box, one must alias it by basically, consuming it into another variable:
let a: Array[U64] ref = consume array // array is "iso"
for (i, item) in a.pairs() do
try a.update(i, item + n)? end
end
This works!!
One more problem I had was that I couldn't do much with the resulting Array[U64] ref. Can't pass it to anyone, for example.
So I wrapped the whole thing into a recover block in order to end up with the same array, but as a val (immutable reference to the array) which is more useful as I can send it to other actors:
let result = recover val
let a: Array[U64] ref = consume array
for (i, item) in a.pairs() do
try a.update(i, item + n)? end
end
a
end
Now I can send result to anyone!

Does Swift have quadratic string concatenation when using var?

In the Swift Language Reference, under String Mutability it says:
You indicate whether a particular String can be modified (or mutated) by assigning it to a variable (in which case it can be modified), or to a constant (in which case it cannot be modified)
It's unclear to me if the "it" that is mutable is the variable or the value.
For example, if I write:
var s = ""
for i in 0...100 {
s += "a"
}
Is it akin to creating an NSMutableString and calling appendString 100 times (i.e. linear cost)?
Or is it akin to creating a series of ever-larger NSString instances and combining them with stringByAppendingString (i.e. quadratic cost)?
Or perhaps it creates some kind of rope structure behind the scenes, so it's immutable and linear in aggregate?
Appending to a collection like this (while String is not itself a collection, you're essentially appending to its characters view with that code) is linear, not quadratic. A string in Swift has an internal buffer whose size is doubled whenever it fills up, which means you will see fewer and fewer reallocations as you repeatedly append. The documentation describes appending in this way as an "amortized" O(1) operation: most of the time appending is O(1), but occasionally it will need to reallocate the string's storage.
Arrays, sets, and dictionaries have the same behavior, although you can also reserve a specific capacity for an array (using reserveCapacity(_:)) if you know you'll be appending many times.
All these collections use "copy-on-write" to guarantee value semantics. Here, x and y share a buffer:
let x = "a"
let y = x
If you mutate x, it gets a new, unique copy of the buffer:
x += "b"
// x == "ab"
// y == "a"
After that, x has its own buffer, so subsequent mutations won't require a copy.
x += "c" // no copy unless buffer is full

MATLAB assign variable name

I have a variable called 'int' with alot of data in it. I would like to find a way to programically rename this variable with a user input. So I can query the user indentifcation information about the data, say the response is 'AA1', I want either rename the variable 'int' to 'AA1' or make 'AA1' a variable that is identical to int.
A problem using the input command arises because it allows the user to assign a value to an already created varialbe, instead of actually creating a variable name. Would using the eval function, or a variation of it, help me achieve this? Or is there an easier way?
Thanks!
Just for the record, int is a rather poor variable name choice.
That aside, you can do what you want as follows
say foo is the variable that holds a string that the user input. You can do the following:
% eliminate leading/trailing whitespace
foo = strtrim(foo);
a = regexp('[a-zA-Z][a-zA-Z0-9_]*',foo));
if numel(a) == 0
fprintf('Sorry, %s is not a valid variable name in matlab\n', foo);
elseif a ~= 1
fprintf('Sorry, %s is not a valid variable name in matlab\n', foo);
elseif 2 == exist(foo,'var')
fprintf('Sorry, %s already in use as a variable name.');
else
eval([foo,' = int']);
end
Assuming int (and now foo) is a structure with field named bar, you can read bar as follows:
barVal = eval([foo,'.bar']);
This is all somewhat clunky.
An alternative approach, that is far less clunky is to use an associative array, and let the user store various values of int in the array. The Matlab approach for associative arrays is Maps. That would be my preferred approach to this problem. Here is an example using the same variables as above.
nameValueMap = containers.Map;
nameValueMap(foo) = int;
The above creates the association between the name stored in foo with the data in the variable int.
To get at the data, you just do the following:
intValue = nameValueMap(foo);

returning multiple dissimilar data structures from R function in PL/R

I have been looking at various discussions here on SO and other places, and the general consensus seems that if one is returning multiple non-similar data structures from an R function, they are best returned as a list(a, b) and then accessed by the indexes 0 and 1 and so on. Except, when using an R function via PL/R inside a Perl program, the R list function flattens the list, and also stringifies even the numbers. For example
my $res = $sth->fetchrow_arrayref;
# now, $res is a single, flattened, stringified list
# even though the R function was supposed to return
# list([1, "foo", 3], [2, "bar"])
#
# instead, $res looks like c(\"1\", \""foo"\", \"3\", \"2\", \""bar"\")
# or some such nonsense
Using a data.frame doesn't work because the two arrays being returned are not symmetrical, and the function croaks.
So, how do I return a single data structure from an R function that is made up of an arbitrary set of nested data structures, and still be able to access each individual bundle from Perl as simply $res->[0], $res->[1] or $res->{'employees'}, $res->{'pets'}? update: I am looking for an R equiv of Perl's [[1, "foo", 3], [2, "bar"]] or even [[1, "foo", 3], {a => 2, b => "bar"}]
addendum: The main thrust of my question is how to return multiple dissimilar data structures from a PL/R function. However, the stringification, as noted above, and secondary, is also problematic because I convert the data to JSON, and all those extra quotes just add to useless data transferred between the server and the user.
I think you have a few problems here. The first is you can't just return an array in this case because it won't pass PostgreSQL's array checks (arrays must be symmetric, all of the same type, etc). Remember that if you are calling PL/R from PL/Perl across a query interface, PostgreSQL type constraints are going to be an issue.
You have a couple of options.
You could return setof text[], with one data type per row.
you could return some sort of structured data using structures PostgreSQL understands, like:
CREATE TYPE ab AS (
a text,
b text
);
CREATE TYPE r_retval AS (
labels text[],
my_ab ab
);
This would allow you to return something like:
{labels => [1, "foo", 3], ab => {a => 'foo', b => 'bar'} }
But at any rate you have to put it into a data structure that the PostgreSQL planner can understand and that is what I think is missing in your example.