code executes perfectly outside of a function, but not inside [duplicate] - python

This question already has answers here:
Running exec inside function
(3 answers)
Creating dynamically named variables in a function in python 3 / Understanding exec / eval / locals in python 3
(2 answers)
Closed 4 years ago.
EDIT: This question is NOT ANSWERED BY THE LINKS ABOVE that a mod added. As I said before in a comment, Python 3 brought changes, and the examples given in those answers were for Python 2. If I compile those in my Python 3 environment, I get the same error as here.
Consider
str = "x = [113, 223]"
exec(str)
print(x[0]) #113
This works perfectly. But if I want this code to be executed in a function, it returns an error NameError: name 'x' is not defined. Here's a minimal working example:
def some_code():
str = "x = [1, 2]"
exec(str)
print(x)
some_code()
What is going on here?
I need a solution to
use exec inside the function (because ultimately its a tkinter function -see the first edit history of this question- and I'm reading this from a file that should be executed
I would like to easily be able to refer to x, because I will need to do that in a lot of places. So using a long line of code to refer to x will be cumbersome.

Naively moving the relevant code to first level scope solved it.
string = "x = [113, 223]"
exec(string)
def some_code():
print(x[0]) #113
Another approach: I started toying around with exec() more and from what I can see exec() writes its results (in this case x) into the locals() and globals() builtin dictionaries. Therefore, the following is another solution to the problem, but it seems rather hacky:
def some_code():
string = "x = [113, 223]"
exec(string)
print(locals()['x'][0]) #113
some_code()
In the same manner, you can define your own dictionary for use instead of locals() where exec() stores x, which in my opinion is much cleaner:
exec_results = {}
def some_code():
string = "x = [113, 223]"
exec(string, None, exec_results)
print(exec_results['x'][0]) #113
some_code()
I highly discourage using exec() for really simple cases such as this, but if you wish to use it in the future, I highly suggest checking out other threads on the same topic that were created prior to this question, such as running-exec-inside-function and globals and locals in python exec(). Check out the Python docs on exec() to read more about exec() as well.

Related

how to make new flow controls in python? [duplicate]

This question already has answers here:
Can you add new statements to Python's syntax?
(13 answers)
Closed 2 months ago.
Not sure how to explain, I mean statemtents like:
for i in l:
if a==b:
def x():
lambda x:
class spam:
while True:
basically those control statements that end with :
can I create novel ones? (like in snakemake that has a long list of new control statements)
I tried reading documentation, but could not find anything useful.
I just want to make some tools to help develop rules for snakemake.
I am currently using this:
class SM(object):
def __init__(self,**xargs):
self.items = xargs
def __getattribute__(self,attr):
return object.__getattribute__(self, "items")[attr]
input = SM(genome="Genome/genome.fa",
table="rmats/binding_strength.maxent.CLIP.csv")
table = pd.read_csv(input.table,index_col=0)
In that example I can use the class SM to emulate all the input, output, wildcard... then I can just move the code into its rule in the Snakefile without needing to manually edit all the inputs/wildcards/outputs...
However, I will still need to write the "input:".
Is there a way I could make:
input:
table="table.csv"
do
input=SM(table:"table.csv")
#or input=SM(**xargs)
Sorry, but no can do...You would have to modify the language implementation itself (the interpreter actually). When you are programming you are bound by the syntax of the language, you cannot modify the syntax "on the fly". It's not the same as e.g. defining functions, classes and whatnot.
Take a look at these:
Can you add new statements to Python's syntax?
How to make custom reserved keywords in python3
Here's the most comprehensive answer to this kind of questions imho:
https://stackoverflow.com/a/9108164/15923186

Using a list comprehension and string formatting on class properties [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 10 months ago.
Here is the basic class code:
class test:
for i in range(10):
exec(f'a{i}={i+1}')
My first attempt to create the list a_all was to do the following:
exec(f'a_all=[test.ak for k in range(0,10,2)]')
However, this doesn't work as exec does not 'unstring' ak the way I want it to. Other attempts failed because the exec function returns None. I'm not even confident anymore that exec could actually work.
Your non-listcomp code works as written (kinda surprised by that), defining attributes of test, so just use that if it's what you need (it's almost certainly a bad idea, but you do you).
This doesn't work in your listcomp code because:
test doesn't exist until the class definition completes (after you dedent at the end), so test.ANYTHING doesn't work inside the definition of test (you assign to top-level names, and they become attributes of test when the class finishes being defined, but they're just scoped names without test. qualification before then)
Omitting test doesn't work in Python 3 because listcomps have their own scope in Python 3; even if you fake it out to assign to each of your names in turn, the iteration variables don't leak to outer scope on Python 3.
In any event, what you're doing is nonsensical:
Your plain for loop code works, but
It's a bad idea; just have a single class attribute of the list and have users index it as needed. There's basically never a good reason to have a programmatically generated list of numbered variable names. That's reinventing lists, badly.
So just use:
class test:
a = range(0, 10, 2) # Or list(range(0, 10, 2)) if it must be mutable
and user's can do test.a[0], test.a[3], whatever they need.
You can use setattr and getattr to set class attributes.
class test:
def __init__(self):
for i in range(10):
setattr(self, f"a{i}", i + 1)
t = test()
for i in range(10):
print(f"{t.a1=} a{i}={getattr(t, f'a{i}')=}")

is there any alternative in python to replace the variable in runtime like in unix shell script {!variableName} [duplicate]

This question already has answers here:
How can I select a variable by (string) name?
(5 answers)
How do I create variable variables?
(17 answers)
Closed 2 years ago.
In unix shell script:
if I call
function_name "${!variable}" -> variable will replaced during the execution/runtime
is there something alternative exists in python? there are some other logic involved prior creating the variable. But I'm interested in {!variable} alternative.
You are looking for the eval function:
a = "there"
b = "a"
eval(b)
Yielding the output:
'there'
Of course, the eval function, while being a bit more verbose than the bash indirect variable reference, is also much more versatile, as you can have the indirectly referenced variable (b in this case), contain any python expression.
In python functions are 1st class objects. Which means you can pass them around just like any variable.
def print_this():
print('this')
def print_that():
print('that')
p1 = print_this
p2 = print_that
p1()
p2()
So you don't need to use eval.

what is the meaning of eval() in x=eval(input("hello"))? [duplicate]

This question already has answers here:
What does Python's eval() do?
(12 answers)
Closed 9 years ago.
what does x=eval(input("hello")) mean, doesn't it suppose to be instead of eval() something like int? I thought of x as a variable that belong to some class that determine its type, does eval include all known classes like int float complex...?
eval, like the documentation says, evaluates the parameter as if it were python code. It can be anything that is a valid python expression. It can be a function, a class, a value, a loop, something malicious...
Rule of thumb: Unless there is no other choice, don't use it. If there is no other choice, don't use it anyway.
eval() will interpret the content typed by the user during the input(). So if the user type x+1 with x equals to 1 in locals, it will output 2 (see below).
An extract from the documentation:
The expression argument is parsed and evaluated as a Python expression (technically speaking, a condition list) using the globals and locals dictionaries as global and local namespace.
>>> x = 1
>>> print eval('x+1')
2
It can be dangerous, since the user can type whatever he wants, like... some Unix command. Don't use it, unless you know what you are doing (even so, it leads to serious security flaws).

How to avoid using 'self' so much [duplicate]

This question already has answers here:
How to avoid explicit 'self' in Python?
(11 answers)
python self-less
(3 answers)
Closed 9 years ago.
I am writing a program to simulate a small physical system and have become more and more annoyed as I write things like this:
K = 0.5 * self.m * self.v**2
In the case above, the equation is short and pretty understandable, but I have situations in which there is so much self that the whole thing ends up looking like a mess. I am aware that python always requires self to refer to class members, but is there a way to to make the code not look like a mosaic of self's?
EDIT: I usually do things such as:
var = self.var
and keep on using var instead of self.var. Later I do:
self.var = var
but this seems really stupid. What would be the pythonic way to solve this problem?
For messy parts I'd use Python modules and "module-level variables" instead of classes.
If all you want to do is save some keystrokes, you can always rename self to s:
class MyClass(object):
def kinetic_energy(s): # use s instead of self for brevity
return 0.5 * s.m * s.v**2
This saves you 3 characters per use of self. This goes against the standard convention, but nothing is stopping you from doing this. I would advice against doing this in general code, but it might be justified if it makes some very long formulas more readable. Do mention the unusual choice in a comment, in case anyone else has to read your code when you are long gone.
I guess it's possible to use some black magic in Python and come up with a context manager, which will take an object and put all its attribute in the context's locals(), and assign it back to object in the __exit__ function.
Found this https://code.google.com/p/ouspg/wiki/AnonymousBlocksInPython which may help.

Categories