Is it possible to run python variable declarations from a string? - python

This is the behaviour I'm looking for...
"a = 2" # execute this line
print a
> 2
I know about the exec statement but I need it to work in python 2 and 3 and python 3 does not allow exec to create local variables. Is there another way around this?
EDIT: Like I said - I know that I can't use exec, the accepted answer of the supposed duplicate is saying to use exec.

I dont necessarilly think this is a good idea ...
import ast
def parse_assignment(s):
lhs,rhs = s.split("=",1)
globals()[lhs] = ast.literal_eval(rhs)
parse_assignment("hello=5")
print(hello)
parse_assignment("hello2='words'")
print(hello2)
parse_assignment("hello3=[1,'hello']")
print(hello3)
https://repl.it/repls/BiodegradableLiveProgrammer

Related

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

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.

Appending tabs to all print statements in Python

I'm writing a Python console application, and I would like its output to be tabbed one tab over to set it apart from the command line.
Is there a single-command way to have tabs in front of all print statements without having to type each one explicitly?
Thank you!
There isn't any setting in Python to be able to do that, the easiest way would be to create a new function like so.
def printTab(*args):
args = ("\t",)+args
print(*args)
Comment on other answers:
If you let your new function take a single argument, rather than multiple arguments (using *args, you lose a lot of the functionality in the Python 3 print function.
What you'll want to do is just create an alternate print command for this specific use. It might look something like this:
from __future__ import print_function
def print_tabbed(str_to_print):
print('\t{}'.format(str_to_print))
While there may be a way to do what you ask (see this link if that's really what you want), I think it's a bad idea and you could improve a bit on this solution.
If you define a function like this :
def printWithTab("text"):
print("\t{}").format(text)
You could use this function instead.
>>>print(test)
test
>>> printWithTab("test")
test
(assuming python 3+)

Python 3: Can we avoid repeating an instance name when calling several of its methods?

I now (or so I have read) that it is not possible in Python 2.x, and can't find it for Python 3 either, but maybe I don't know how to search for it...
It easier to explain it with a simple Python example:
for i in range(11):
one_turtle.penup()
one_turtle.forward(50)
one_turtle.down()
one_turtle.forward(8)
one_turtle.up()
one_turtle.forward(8)
one_turtle.stamp()
one_turtle.forward(-66)
one_turtle.left(360/12)
I'd like to avoid repeating "one_turtle" the same way you can do in VBA, which it would result in something similar to this:
For i = 1 To 11
With one_turtle.penup()
.forward(50)
.down()
.forward(8)
.up()
.forward(8)
.stamp()
.forward(-66)
.left(360/12)
The code resulting from the With keyword is much clearer and easy to write and read (it'll need an End With and a Next lines but I wanted to focus the discussion). One of the main reasons I have decided to learn Python is because it is said to be very neat and "zen-like" to program. Is it really not possible to do this?
In your definition of all these member-methods, simply return self.
eg. Change definition of penup() like this:
def penup(self):
# Your logic
return self
The ideal solution is I think already posted, returning self is simply the cleanest way. However if you're not able to edit the turtle object or whatever, you can create an alias:
forward = one_turtle.forward
... some code ...
forward()
Now the function forward just applies forward to one_turtle, simple example
s = "abc"
x = s.upper
print(x()) # prints "ABC"

Assignment in conditional not permitted in Python?

Why is code like
if a = "hello":
pass
invalid in Python? The a = "Hello" is just a expression whose value is the Rvalue. It's valid in most languages like C or php. Some opinions?
While Python will allow you to chain assignment,
a = b = "hello"
it will not allow you to use it in an expression,
"hi" > b = "hello" # => Syntax error
This is for safety, to keep you from accidentally using = when you meant ==
This is intentionally made illegal in python as allowing it is a huge source of error and making it illegal is a minor inconvenience.
See the Design and History FAQ
My experience in python is that this is basically right. I rarely miss not being able to do this.

Why would people use globals() to define variables

I've come across recently a number of places in our code which do things like this
...
globals()['machine'] = otherlib.Machine()
globals()['logger'] = otherlib.getLogger()
globals()['logfile'] = datetime.datetime.now().strftim('logfiles_%Y_%m_%d.log')
and I am more than a little confused as to why people would do that, rather than doing
global machine
machine = otherlib.Machine()
and so on.
Here is a slightly anonymised function which does this, in full:
def openlog(num)
log_file = '/log_dir/thisprogram.' + num
if os.path.exists(log_file):
os.rename(log_file, log_file + '.old')
try:
globals()["log"] = open(log_file, 'w')
return log
except:
print 'Unable to open ' + log_file
sys.exit(1)
It confuses the hell out of pylint (0.25) as well me.
Is there any reason for coding it that way? There's minimal usage of eval in our code, and this isn't in a library
PS I checked Reason for globals() in python but it doesn't really answer as to why you'd use this for setting globals in a program
Maybe the function uses a local variable with the same name as the global one, and the programmer didn't want to bother changing the variable name?
def foo(bar):
global bar # SyntaxError
bar = bar + 1
def foo(bar):
globals()['bar'] = bar + 1
foo(1)
print(bar) # prints 2
Another use case, albeit still a bit specious (and clearly not the case in the example function you gave), is for defining variable names dynamically. This is rarely, if ever, a good idea, but it does come up a lot in questions on this site, at least. For example:
>>> def new_variable():
... name = input("Give your new variable a name! ")
... value = input("Give your new variable a value! ")
... globals()[name] = value
...
>>> new_variable()
Give your new variable a name! foo
Give your new variable a value! bar
>>> print(foo)
bar
Otherwise, I can think of only one reason to do this: perhaps some supervising entity requires that all global variables be set this way, e.g. "in order to make it really, really clear that these variables are global". Or maybe that same supervising entity has placed a blanket ban on the global keyword, or docks programmer pay for each line.
I'm not saying that any of these would be a good reason, but then again, I truly can't conceive of a good reason to define variables this way if not for scoping purposes (and even then, it seems questionable...).
Just in case, I did a timing check, to see if maybe the globals() call is faster than using the keyword. I'd expect the function call + dictionary access to be significantly slower, and it is.
>>> import timeit
>>> timeit.timeit('foo()', 'def foo():\n\tglobals()["bar"] = 1',number=10000000)
2.733132876863408
>>> timeit.timeit('foo()', 'def foo():\n\tglobal bar\n\tbar = 1',number=10000000)
1.6613818077011615
Given the code you posted and my timing results, I can think of no legitimate reason for the code you're looking at to be written like this. Looks like either misguided management requirement, or simple incompetence.
Are the authors PHP converts? This is a valid code in PHP:
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
See this for more examples. If someone was used to this way of writing the code, maybe they just used the closest matching way of doing it in Python and didn't bother to check for alternatives.
You'd sometimes use a superglobal $GLOBAL variable to define something, because although global keyword exists in PHP, it will only import existing variables - it cannot create a new variable as far as I know.

Categories