Use a String to Access a Local Variable by Name

Access local variable by name

You can use debug.getlocal() and debug.setlocal() in the debug library:

function setLocal(name, val)
local index = 1
while true do
local var_name, var_value = debug.getlocal(2, index)
if not var_name then break end
if var_name == name then
debug.setlocal(2, index, val)
end
index = index + 1
end
end

Test:

local var1
local var2
setLocal("var1", 42)
print(var1)

Output: 42

How do I access a local variable dynamically (via a String form of its name) from a closure scope?

You're mixing up local variables (which are not properties of an object) with properties (which are not local variables). There is no answer to your question, or, rather, the answer is "it can't be done".

Use a string to access a local variable by name

You need to provide more details of your code setup to get a good answer (or for me to figure out which question this is a duplicate of :). What kind of variables are referenced by $1? Here are some guesses:

  1. If this is actually a method on the same instance, you can invoke this method by:

    # Same as "self.foo" if $1 is "foo"
    self.send($1).description.downcase
  2. If these are instance variables, then:

    # Same as "@foo.description.downcase"
    instance_variable_get(:"@#{$1}").description.downcase
  3. If these are local variables, you can't do it directly, and you should change your code to use a Hash:

    objs = {
    'foo' => ...,
    'key' => Item.new( :name => "Key", :description => "a key" )
    }
    objs['jim'] = ...
    case some_str
    when /^read (.+)$/
    puts "Reading #{$1}:"
    puts objs[$1].description.downcase
    end

Access a methods local variable value using a string containing the variable name in .Net

Local variables aren't representing in reflection. You can see globals because they're members of a type. Locals, however, are just slots on the current stack, and that stack isn't exposed to the reflection APIs.

The only place that the call stack is exposed programmatically is in the stack trace in an exception. You could throw an exception deliberately, catch it, and pick through the stack trace. But it would be a bad, bad, idea, and extremely slow.

How to get local variable by its name in JS?

You don't want to use eval; a locally scoped object might be your best option:

var x = function(){
var self = {};
self.example_var = 'Local var example';

var var_name = 'example_var';

alert('Local var value is: ' + self[var_name]);
}

Get value from string representing local variable

You can use eval.

variable = 22
eval("variable")
# => 22

However eval can be nasty. If you dont mind declaring an instance variable, you can do something like this too:

@variable = 22
str = "variable"
instance_variable_get("@#{str}")
# => 22

Getting the name of a variable as a string

TL;DR

Use the Wrapper helper from python-varname:

from varname.helpers import Wrapper

foo = Wrapper(dict())

# foo.name == 'foo'
# foo.value == {}
foo.value['bar'] = 2

For list comprehension part, you can do:

n_jobs = Wrapper(<original_value>) 
users = Wrapper(<original_value>)
queues = Wrapper(<original_value>)
priorities = Wrapper(<original_value>)

list_of_dicts = [n_jobs, users, queues, priorities]
columns = [d.name for d in list_of_dicts]
# ['n_jobs', 'users', 'queues', 'priorities']
# REMEMBER that you have to access the <original_value> by d.value

I am the author of the python-varname package. Please let me know if you have any questions or you can submit issues on Github.

The long answer

Is it even possible?

Yes and No.

We are retrieving the variable names at runtime, so we need a function to be called to enable us to access the previous frames to retrieve the variable names. That's why we need a Wrapper there. In that function, at runtime, we are parsing the source code/AST nodes in the previous frames to get the exact variable name.

However, the source code/AST nodes in the previous frames are not always available, or they could be modified by other environments (e.g: pytest's assert statement). One simple example is that the codes run via exec(). Even though we are still able to retrieve some information from the bytecode, it needs too much effort and it is also error-prone.

How to do it?

First of all, we need to identify which frame the variable is given. It's not always simply the direct previous frame. For example, we may have another wrapper for the function:

from varname import varname

def func():
return varname()

def wrapped():
return func()

x = wrapped()

In the above example, we have to skip the frame inside wrapped to get to the right frame x = wrapped() so that we are able to locate x. The arguments frame and ignore of varname allow us to skip some of these intermediate frames. See more details in the README file and the API docs of the package.

Then we need to parse the AST node to locate where the variable is assigned value (function call) to. It's not always just a simple assignment. Sometimes there could be complex AST nodes, for example, x = [wrapped()]. We need to identify the correct assignment by traversing the AST tree.

How reliable is it?

Once we identify the assignment node, it is reliable.

varname is all depending on executing package to look for the node. The node executing detects is ensured to be the correct one (see also this).

It partially works with environments where other AST magics apply, including pytest, ipython, macropy, birdseye, reticulate with R, etc. Neither executing nor varname is 100% working with those environments.

Do we need a package to do it?

Well, yes and no, again.

If your scenario is simple, the code provided by @juan Isaza or @scohe001 probably is enough for you to work with the case where a variable is defined at the direct previous frame and the AST node is a simple assignment. You just need to go one frame back and retrieve the information there.

However, if the scenario becomes complicated, or we need to adopt different application scenarios, you probably need a package like python-varname, to handle them. These scenarios may include to:

  1. present more friendly messages when the source code is not available or AST nodes are not accessible
  2. skip intermediate frames (allows the function to be wrapped or called in other intermediate frames)
  3. automatically ignores calls from built-in functions or libraries. For example: x = str(func())
  4. retrieve multiple variable names on the left-hand side of the assignment
  5. etc.

How about the f-string?

Like the answer provided by @Aivar Paalberg. It's definitely fast and reliable. However, it's not at runtime, meaning that you have to know it's foo before you print the name out. But with varname, you don't have to know that variable is coming:

from varname import varname

def func():
return varname()

# In external uses
x = func() # 'x'
y = func() # 'y'

Finally

python-varname is not only able to detect the variable name from an assignment, but also:

  • Retrieve variable names directly, using nameof
  • Detect next immediate attribute name, using will
  • Fetch argument names/sources passed to a function using argname

Read more from its documentation.

However, the final word I want to say is that, try to avoid using it whenever you can.

Because you can't make sure that the client code will run in an environment where the source node is available or AST node is accessible. And of course, it costs resources to parse the source code, identify the environment, retrieve the AST nodes and evaluate them when needed.

How to get the value of a variable given its name in a string?

If it's a global variable, then you can do:

>>> a = 5
>>> globals()['a']
5

A note about the various "eval" solutions: you should be careful with eval, especially if the string you're evaluating comes from a potentially untrusted source -- otherwise, you might end up deleting the entire contents of your disk or something like that if you're given a malicious string.

(If it's not global, then you'll need access to whatever namespace it's defined in. If you don't have that, there's no way you'll be able to access it.)

Javascript: Get access to local variable or variable in closure by its name

I'm not aware of anything built into JavaScript to reference local variables like that (though there probably should be considering all variables are internally referenced by strings).

I'd suggest keeping all your variables in an object if you really need to access by string:

var variables = {
"j": 1
};
alert(variables["j"]);

Update: It kind of bugs me that there's no way to do this like you want. Internally the variable is a mutable binding in the declarative environment records. Properties are bound to the object they're a property of through the object's environment records, but there's actually a way to access them using brackets. Unfortunately, there's no way to access the declarative environment records the same way.



Related Topics



Leave a reply



Submit