Parsing list to create python code - python

I have a list that I have successfully converted into a python statment
ex:
from operator import mul,add,sub,abs
l = ['add(4,mul(3,abs(-3)))']
I was wondering what would I use to RUN this string as actual python code? I should be expecting a output of 13. I want to input the 0th value of the list into a function that is able to run this value as actual python code.

You don't want to run this as Python code. You're trying to parse expressions in some language that isn't Python, even if it may be superficially similar. Even if it's a proper subset of Python, unless, say, __import__('os').system('rm -rf /') happens to be a valid string in the language that you want to handle by erasing the hard drive, using eval or exec is a bad idea.
If the grammar is a proper subset of Python, you can still use the ast module for parsing, and then write your own interpreter for the parsed nodes.
However, I think what you really want to do here is build a very simple parser for your very simple language. This is a great opportunity to learn how to use a parsing library like pyparsing or a parser-generator tool like pybison, or to build a simple recursive-descent parser from scratch. But for something this simple, even basic string operations (splitting on/finding parentheses) should be sufficient.
Here's an intentionally stupid example (which you definitely shouldn't turn in if you want a good grade) to show how easy it is:
import operator
OPERATORS = operator.__dict__
def evaluate_expression(expr):
try:
return int(expr)
except ValueError:
pass
op, _, args = expr.rpartition('(')
rest, _, thisop = op.rpartition(',')
args = args.rstrip(')').split(',')
argvalues = map(int, args)
thisvalue = OPERATORS[thisop](*argvalues)
if rest:
return evaluate_expression('{},{}'.format(rest, thisvalue))
return thisvalue
while True:
expr = input()
print(evaluate_expression(expr))
Normally, you want to find the outermost expression, then evaluate it recursively—that's a lot easier than finding the rightmost, substituting it into the string, and evaluating the result recursively. Again, I'm just showing how easy it is to do even if you don't do it the easy way.

use exec like this:
exec('add(4,mul(3,abs(-3)))')
That should work
more about exec

If you want to evaluate a Python expression, use eval. This returns the value of the evaluated expression. So, for example:
>>> eval(l[0])
13
>>> results = [eval(expr) for expr in l]
>>> results
[13]
However, any time you find yourself using eval (or exec or related functionality), you're almost always doing something wrong. This blog post explains some of the reasons why.

since you're evaluating an expression, eval would suit you better than exec. Example:
x = -3
y = eval('add(4,mul(3,abs(x)))')
print y
Note the security implication of exec and eval, since they can execute arbitrary code, including for example deleting all files you have access, installing Trojans to your doc files, etc.
Check out also ast.literal_eval for python 2.6+.

Related

Is there a way to convert a list containing arithmetic operations which is written as a string into an actual list?

I would like to convert a String like:
s = "[2-1,2,3]"
into a list, like:
a = [1,2,3]
I tried it with json:
s = "[2-1,2,3]"
a = json.loads(s)
but it can't handle 2-1.
Is there an easy method to convert strings into any kind of datatype?
Yes. And as much as it pains me to say it, eval is your friend here, as even ast.literal_eval cannot parse this.
Please read this first: eval: bad practice?, and please ensure you have complete control over the expressions being evaluated.
To help lessen the expressions being evaluated, I've wrapped this solution in regex, to extract only numbers and (in this case) the minus sign.
Obviously, this might need tweaking for your specific use case, this this should give you a boiler-plate (or at least an idea) from which to start.
Example code:
import re
s = "[2-1,2,3]"
rexp = re.compile('[\d-]+')
out = []
for exp in rexp.findall(s):
out.append(eval(exp))
Or, if you prefer a one-liner:
out = [eval(exp) for exp in rexp.findall(s)]
Output:
[1, 2, 3]
This is a common problem to tackle while writing compilers. Usually this comes under lexing.
A parser would usually have a list of tokens, watch for the tokens and then pass it to a parser and then the compiler.
Your problem cannot be completely solved with a lexer though since you also require the 2-1 to evaluate to 1. In this case, I would suggest using eval like #Daniel Hao suggested since it is a simple and clean way of achieving your goal. Remember about the caveats(both security and otherwise) while using it though. (especially, in production)
If you are interested in the parsing though, check this out:
https://craftinginterpreters.com/contents.html
https://tomassetti.me/parsing-in-python/

How to make an operation from a textfile and then write in another file

I need to do something like this :
expresii.txt
3+5
2-3
iesire.txt
3+5=8
2-3=-1
I converted "expresii.txt" in a list, but I don't know how to read an operator and make the operation.
f = open("expresii.txt", "r")
with open("iesire.txt",'w',encoding = 'utf-8') as f:
List = open("expresii.txt").readlines()
List = [x.strip() for x in List]
print(List)
The simplest option would be go with eval, however it's not safe. On the other edge is to program whole parser by yourself, which includes checking the type of the input (weather it's number or operator), transforming them into python operators, checking the order of execution etc... Which might be a lot of work.
Talking about some safer and easier solutions these references might be helpful:
numexpr lib Safely evaluate simple string equation
ast, asteval, Pyparsing Evaluating a mathematical expression in a string

How to use gettext with python >3.6 f-strings

Previously you would use gettext as following:
_('Hey {},').format(username)
but what about new Python's f-string?
f'Hey {username}'
'Hey {},' is contained in your translation dictionary as is.
If you use f'Hey {username},', that creates another string, which won't be translated.
In that case, the format method remains the only one useable, but you could approach the f-string features by using named parameters
_('Hey {username},').format(username=username)
or if you have a dictionary containing your data, this cool trick where format picks the required information in the input dictionary:
d = {"username":"John", "city":"New York", "unused":"doesn't matter"}
_('Hey {username} from {city},').format(**d)
My solution is to make a function f() which performs the f-string interpolation after gettext has been called.
from copy import copy
from inspect import currentframe
def f(s):
frame = currentframe().f_back
kwargs = copy(frame.f_globals)
kwargs.update(frame.f_locals)
return eval(s.format(**kwargs))
Now you just wrap _(...) in f() and don’t preface the string with an f:
f(_('Hey, {username}'))
Note of caution
I’m usually against the use of eval as it could make the function potentially unsafe, but I personally think it should be justified here, so long as you’re aware of what’s being formatted. That said use at your own risk.
Remember
This isn’t a perfect solution, this is just my solution. As per PEP 498 states each formatting method “have their advantages, but in addition have disadvantages” including this.
For example if you need to change the expression inside the string then it will no longer match, therefore not be translated unless you also update your .po file as well. Also if you’re not the one translating them and you use an expression that’s hard to decipher what the outcome will be then that can cause miscommunication or other issues in translation.

String to Python statement?

I want to convert a string to a Python statement.
Taking string input from a text file e.g. 'dataframe['Column_name'].sum()'
Executing the string as a Python statement e.g. dataframe['Column_name'].sum()
Storing the result in some variable
It's possible to do this, but not recommended. You do not have any control over what the string contains if it comes from the user. There is probably a better way to achieve what you really want.
If you really, absolutely, unavoidably have to, you can use eval:
x = eval('dataframe["Column_name"].sum()')
But it is probably easier to only take, for example, the column name from the user and use that in a function call:
column_name = "Column_name" # or read it from the file
x = dataframe[column_name].sum()
#previous code
with open("file.txt","r") as f:
x = eval(f.readline())
#the rest of the code, using x however you want
I wouldn't do it if other users are supposed to be able to use the script however they want. If this is for learning purposes of for your own use, it's up to you.

Python- stuck trying to create a "free hand" calculator

I'm trying to create a calculator program in which the user can type an equation and get an answer. I don't want the full code for this, I just need help with a specific part.
The approach I am trying to take is to have the user input the equation as a string (raw_input) and then I am trying to convert the numbers from their input to integers. After that I need to know how I can get the operands to do what I want them to do depending on which operand the user uses and where it is in the equation.
What are some methods I might use to accomplish this task?
Here is basically what I have right now:
equation_number = raw_input("\nEnter your equation now: ")
[int(d) for d in equation_number if d.isdigit()]
Those lines are just for collecting input and attempting to convert the numbers into integers. Unfortunately, it does not seem to be working very well and .isdigit will only work for positive numbers anyway.
Edit- aong152 mentioned recursive parsing, which I looked into, and it appears to have desirable results:
http://blog.erezsh.com/how-to-write-a-calculator-in-70-python-lines-by-writing-a-recursive-descent-parser/
However, I do not understand the code that the author of this post is using, could anyone familiarize me with the basics of recursive parsing?
The type of program you are trying to make is probably more complicated than you think
The first step would be separating the string into each argument.
Let's say that the user inputs:
1+2.0+3+4
Before you can even convert to ints, you are going to need to split the string up into its components:
1
+
2.0
+
3
+
4
This will require a recursive parser, which (seeing as you are new to python) maybe be a bit of a hurdle.
Assuming that you now have each part seperately as strings,
float("2.0") = 2.0
int(2.0) = 2
Here is a helper function
def num (s):
try:
return int(s)
except exceptions.ValueError:
return int(float(s))
instead of raw_input just use input because raw_input returns a string and input returns ints
This is a very simple calculator:
def calculate():
x = input("Equation: ")
print x
while True:
calculate()
the function takes the input and prints it then the while loop executes it again
im not sure if this is what you want but here you go and also you should make a way to end the loop
After using raw_input() you can use eval() on the result to compute the value of this string. eval() evaluates any valid Python expression and returns the outcome.
But I think this is not to your liking. You probably want to do more by yourself.
So I think you should have a look at the re module to split the input using regular expressions into tokens (sth like numbers and operators). After this you should write a parser which gets the token stream as input. You should decide whether this parser shall just return the computed value (e. g. a number) or maybe an abstract syntax tree, i. e. a data structure which represents the expression in an object-oriented (instead of character-oriented) way. Such an Absy could then be evaluated to get the final result.
Are you familiar with regular expressions? If not, it's probably a good idea to first learn about them. They are the weak, non-recursive cousin of parsing. Don't go deep, just understand the building blocks — A then B, A many times, A or B.
The blog post you found is hard because it implements the parsing by hand. It's using recursive descent, which is the only way to write a parser by hand and keep your sanity, but it's still tricky.
What people do most of the time is only write a high level grammar and use a library (or code generator) to do the hard work of parsing.
Indeed he had an earlier post where he uses a library:
http://blog.erezsh.com/how-to-write-a-calculator-in-50-python-lines-without-eval/
At least the beginning should be very easy. Things to pay attention to:
How precedence arises from the structure of the grammar — add consists of muls, not vice versa.
The moment he adds a rule for parentheses:
atom: neg | number | '(' add ')';
This is where it really becomes recursive!
6-2-1 should parse as (6-2)-1, not 6-(2-1). He doesn't discuss it, but if you look
carefully, it also arises from the structure of the grammar. Don't waste tome on this; just know for future reference that this is called associativity.
The result of parsing is a tree. You can then compute its value in a bottom-up manner.
In the "Calculating!" chapter he does that, but the in a sort of magic way.
Don't worry about that.
To build a calculator yourself, I suggest you strip the problem as much as possible.
Recognizing where numbers end etc. is a bit messy. It could be part of the grammar, or done by a separate pass called lexer or tokenizer.
I suggest you skip it — require the user to type spaces around all operators and parens. Or just assume you're already given a list of the form [2.0, "*", "(", 3.0, "+", -1.0, ")"].
Start with a trivial parser(tokens) function that only handles 3-element expressions — [number, op, number].
Return a single number, the result of the computation. (I previously said parsers output a tree which is processed later. Don't worry about that, returning a number is simpler.)
Write a function that expects either a number or parentheses — in the later case it calls parser().
>>> number_or_expr([1.0, "rest..."])
(1.0, ["rest..."])
>>> number_or_expr(["(", 2.0, "+", 2.0, ")", "rest..."])
(4.0, ["rest..."])
Note that I'm now returning a second value - the remaining part of the input. Change parser() to also use this convention.
Now Rewrite parser() to call number_or_expr() instead of directly assuming tokens[0] and tokens[2] are numbers.
Viola! You now have a (mutually) recursive calculator that can compute anything — it just has to be written in verbose style with parens around everything.
Now stop and admire your code, for at least a day :-) It's still simple but has the essential recursive nature of parsing. And the code structure reflects the grammar 1:1 (which is the nice property of recursive descent. You don't want to know how the other algorithms look).
From here there many improvements possible — support 2+2+2, allow (1), precedence... — but there are 2 ways to go about it:
Improve your code step by step. You'll have to refactor a lot.
Stop working hard and use a parsing library, e.g. pyparsing.
This will allow you to experiment with grammar changes faster.

Categories