I have an array of numbers that the user input. Now, I want the user to enter an expression (for example, sin (x)) and I want to evaluate the expression using the numbers from the array.
I don't know how to get the expression as an input from the user and then to evaluate it based on the array.
So far I have:
collection = list()
number = input("Enter the number of elements you want: ")
for i in range(int(number)):
n = input("Enter number:")
collection.append(int(n))
print ('ARRAY: ',collection)
def function_creator():
expr = input("Enter the function(in terms of x):")
x = int(input("Enter the value of x:"))
safe_dict['x'] = x
y = eval(expr, {"__builtins__":None}, safe_dict)
print("y = {}".format(y))
if __name__ == "__main__":
safe_list = ['acos', 'asin', 'atan', 'atan2', 'ceil', 'cos',
'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor',
'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10',
'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt',
'tan', 'tanh']
safe_dict = dict([(k, locals().get(k, None)) for k in safe_list])
function_creator()
I have tried getting the expression using the eval() function in python but couldn't get it to work. For the sake of working in steps, I'm not using the array right now as the x variable in the expression the user inputs. Instead, I'm just trying to evaluate the expression the user inputs with an x of their choice. Any ideas on how to make it work or any other way in which I can get the function as an input?
This code should work for expressions in x such as x*sin(x) + (x+1)*exp(2*x)
from math import * # import sin, cos, tan, etc. into globals
# to allow use by eval
def function_creator(arr):
" allows expressions such as x*sin(x) + x "
expr = input("Enter the function(in terms of x):")
# x is bound locally inside the list comprehension for use by eval
return [eval(expr) for x in arr] # compute expression on each data element
if __name__ == "__main__":
collection = list()
number = input("Enter the number of elements you want: ")
for i in range(int(number)):
n = input("Enter number:")
collection.append(float(n))
print ('ARRAY: ',collection)
result = function_creator(collection)
print(result)
Simple answer
You can import functions into the global scope, and then grab them from globals as follows:
from numpy import sin
collection = list()
number = input("Enter the number of elements you want: ")
for i in range(int(number)):
n = input("Enter number:")
collection.append(int(n))
print ('ARRAY: ',collection)
func_name = input("Enter function: ")
try:
ans = globals()[func_name](collection)
except KeyError:
raise AttributeError('Function not found in namespace!')
print(ans)
Slightly more sophisticated answer
You can try the following code snippet:
import numpy as np
collection = list()
number = input("Enter the number of elements you want: ")
for i in range(int(number)):
n = input("Enter number:")
collection.append(int(n))
print ('ARRAY: ',collection)
func_name = input("Enter function: ")
def getattr_loop(obj,attr):
'''getattr, or getitem, or error, in a loop, forever!'''
spl = attr.split('.')
if len(spl) > 1:
try:
return getattr_loop(getattr(obj,spl[0]),'.'.join(spl[1:]))
except AttributeError as err:
try:
return getattr_loop(obj[spl[0]],'.'.join(spl[1:]))
except KeyError:
raise err
else:
return getattr(obj,spl[0])
# Compute using user defined function
try:
ans = getattr_loop(globals(),func_name)(collection)
except AttributeError:
raise AttributeError('Function not found in namespace!')
print(ans)
getattr_loop is a function which will recursively search obj for attribute attr. The attribute given by attr automatically reads dot notation, and so you can use it to do some nifty tricks. It also has some handling to attempt .__getitem__() if there is no attribute (obj[attr])
The downside is that getattr_loop will give you a RecursionError if you have a really deeply nested attribute in obj.
For example, if one uses the Numpy module as the object:
>>> getattr_loop(np,'random.rand')
This would allow you to access np.random.rand. If you use globals() as is used in the code snippet, it will grab all objects defined at the global scope. So, a user of the above code snippet can type 'np.sin' as the function, and the code will compute np.sin(collection).
If you wish to use sin directly, you'll need to import that directly into the namespace.
Caveat about security
Grabbing things from globals() can be risky from a security perspective. If you need this to be secure, make sure to:
sanitise your inputs
construct an object which only contains the functions that you want someone to be able to access, lest you accidentally allow someone to patch into something like os.remove and do some harm...
Enjoy!
Related
I was trying to make a calculator for newtons method given a function, I've got everything down except that I keep running into an issue when I'm trying to do log of a different base or ln(x).
I'd appreciate the help!
import sympy as sp
x = sp.symbols('x')
# ask for expression and initial guess
expression = input('input function: ')
initial = float(input('input an initial guess: '))
iterate = int(input('input how many times you want it to iterate: '))
# find derivative of function
f_prime = sp.diff(expression, x)
f = sp.lambdify(x, expression, 'numpy')
df = sp.lambdify(x, f_prime, 'numpy')
# newtons method rounded to 8 decimal places
for i in (1, iterate):
i = initial - (f(initial)/df(initial))
initial = round(i, 8)
print(f'The root is {initial} after {iterate} iterations')
Everytime I put in log of a different base it would give me
TypeError: return arrays must be of ArrayType or a name error
for ln(x) it would give me
AttributeError: 'Symbol' object has no attribute 'ln'. Did you mean: 'n'?
The output of your expression = input('input function: ') is of type string. Before creating f = sp.lambdify(...) you need to convert that expression into a symbolic expression. sympify is the command you need to use:
expression = sp.sympify(input('input function: '))
I have a file that I have to read. In every line, there is a name, age, height, and weight. There are a lot of lines in the file and I only need the names. Here is my code:
import random
import string
dictionary = {}
lst = []
with open("persons.dat","r") as file:
for line in file:
items = line.split(',') #this makes this ['Bill Johnson', '31', '196', '93']
key = items[0]
dictionary[key] = []
for i in range(1,len(items)):
dictionary[key].append(int(items[i]))
#print(dictionary)
for key in dictionary.keys():
lst.append(key)
print(lst)
def generateGroup(sizeOfGroup):
for names in range(sizeOfGroup):
random_names = random.choice(lst)
print(random_names)
My code gets all of the names in the list as intended. The code works fine up to generateGroup()
I need a function that would ask for the size of a group (some number) of the list and give random names from that list.
I don't know how to implement that function. I kind of get the logic of the function, but I don't know where I should put the function in the code (like which line).
random.sample does exactly this.
def generateGroup(sizeOfGroup):
print(random.sample(lst, k=sizeOfGroup))
random.sample returns a list. You could accumulate the list yourself
random_names = []
for names in range(sizeOfGroup):
random_names.append(random.choice(lst))
print(random_names)
but random.sample ensures that you won't select the same name twice.
Once generateGroup is defined correctly, you still need to call it with an argument:
while True:
try:
n = int(input("Enter a number: "))
break
except ValueError:
print("That's not an integer, try again")
generateGroup(n)
I am trying to create a new list performing element-wise substruction of two python lists as follows:
from operator import add
number_villains_players = 0
villain_strength = []
player_strength = []
resulten_strength = []
def get_villain_strength(size):
villain_strength = [int(x) for x in input("Enter {} numbers of space separated strength of Villains:".format(size)).split()]
print(villain_strength)
def get_player_strength(size):
player_strength = [int(x) for x in input("Enter {} numbers of space separated energy of Players:".format(size)).split()]
print(player_strength)
def compare_strength():
#resulten_strength = [m-n for (m,n) in zip(player_strength,villain_strength)] #doesn't work
#resulten_strength = [sum(x) for x in zip(player_strength, villain_strength)] #doesn't work
#resulten_strength = [list( map(add, player_strength, villain_strength) )] #doesn't work
resulten_strength = [a*b for a,b in zip(player_strength,villain_strength)] #doesn't work
print(resulten_strength)
def main():
number_villains_players = input("How many Players/Villains?:")
get_villain_strength(number_villains_players)
get_player_strength(number_villains_players)
compare_strength()
if (i > 0 for i in resulten_strength):
print("WIN")
else:
print("LOSE")
main()
But print(resulten_strength) is always empty as [] or [[]]
I have followed all the possible solutions from:
Element-wise addition of 2 lists?
How to mathematically subtract two lists in python? [duplicate]
How to perform element-wise multiplication of two lists in Python?
Can anyone point me where I am going wrong?
You are assigning local lists in methods and they are not global. Thus the top lines defined are always empty. This should fix your problem:
def get_villain_strength(size):
global villain_strength
villain_strength = [int(x) for x in input("Enter {} numbers of space separated strength of Villains:".format(size)).split()]
print(villain_strength)
However it's bad to use globals anywhere. You may want a function with something return.
When you are assigning the same name variable inside a function it will override the global variable's name, until you return from the function. Or to say if you lookup a variable, it first looks up the name in locals(), if nothing found, it'll go globals(). If still nothing found, an exception will be raised.
I'm not sure this is what you're looking for. I made a small modification to your code. I remove your variables declaration and modify your function.
def get_villain_strength(size):
villain_strength = [int(x) for x in input("Enter {} numbers of space separated strength of Villains:".format(size)).split()]
print (villain_strength)
return(villain_strength)
def get_player_strength(size):
player_strength = [int(x) for x in input("Enter {} numbers of space separated energy of Players:".format(size)).split()]
print (player_strength)
return(player_strength)
def compare_strength(x,y):
resulten_strength = [a*b for a,b in zip(x,y)]
return(resulten_strength)
def main():
number_villains_players = input("How many Players/Villains?:")
x = get_villain_strength(number_villains_players)
y = get_player_strength(number_villains_players)
print (compare_strength(x,y))
It doesn't want to print out the list entered by the user. I think the problem is in list= []
from HeapClass import Heap
def minHeap(list):
heap = Heap() #
lst = eval(input("Enter list of numbers: "))
for v in lst:
heap.add(v)
for i in range(len(list)):
list[len(list) - 1 - i] = heap.remove()
def main():
list = [] This think the problem is here because it doesn't return a list but when I write list = lst... It does not work either
minHeap(list)
for v in list:
print(str(v)+ " ", end = " ")
main()
You're using list as a variable name. Rename it to something else here def minHeap(list):, here def main(): list = [] and everywhere else. You don't need it.
Also, you don't need the evil eval() :)
If you want user input of the format "1,2,3" (comma-separated numbers) to be cast to a list of integers, you could instead do:
lst = list(input("Enter list of numbers: ")) in python2.7
or
lst = [int(x) for x in input("Enter list of numbers: ").split(",")] in python3.
To see why using list as a variable name is bad/confusing, try the following:
Type list((1,2,3)) in your interpreter. It should transform the tuple (1,2,3) to a list and return [1, 2, 3]. All is well.
Now try typing list = [] and repeat list((1,2,3)).
You should now get an error saying TypeError: 'list' object is not callable and you won't be able to cast anything to list again; it effectively overrides the datatype so what used to be <type 'type'> is now a single list of <type 'list'>. Overriding built-in stuff gets weird; best to avoid it unless you're intentionally doing meta-programming.
The problem is I have to write a program which takes in a list of words and an integer and returns the words whose length is longer than that integer. I have to use filter() only.
This is what I wrote :
def filter(list,integer):
largenum = list(filter(lambda x: len(x) > integer, list ))
return largenum
inp = input("Enter the words: ").split()
intr = input("Enter the integer: ").split()
print (filter(inp,intr))
When I run this and give the inputs, it gives an error:
Runtime error: Maximum recursion depth exceeded.
What am I doing wrong?
edit: I got it. Such a silly mistake(s) XD.
1.) I changed filter(list,integet) to filterthis(string,integer)
2.) intr = input("Enter the integer: ").split() to intr = int(input("Enter the integer: ")
You are passing integer as list.So use integer[0].Then input returns str.So use int(integer[0]).
Then you are using filter as your function name.So this will override the builtin function filter.Also you are passing your list as variable list.It will also override the builtin callable list.You can try this
def myfilter(mylist,integer):
largenum = list(filter(lambda x: len(x) > int(integer[0]), mylist ))
return largenum
inp = input("Enter the words: ").split()
intr = input("Enter the integer: ").split()
>>>print(myfilter(inp,intr))
You have written filter function which calls itself without a base case.
Rename your filter function.
In [8]: def my_filter(l, i):
...: largenum = filter(lambda x: len(x)> i, l) # if python3, use list(filter)
...: return largenum
...:
In [9]: inp = ["LOL", "DA", "YAYASTRING"]
In [10]: intr = 2
In [11]: my_filter(inp, intr)
Out[11]: ['LOL', 'YAYASTRING']
Your version of filter will shadow the python built-in which has the same name. So when you make a call to it from inside your filter, it's not really to the built-in you are intending to call, but to your function itself. Since there is no stopping rule for the recursion, it ends up exceeding permissible stack depth.
Same goes for list. The function argument with the same name will shadow the builtin python list container.
Also, you'll need to cast the second argument to int before passing it to the function.
For code:
def fil(lst, integer):
return filter(lambda x: len(x) > integer, lst)
>>> fil(['Hello', 'how', 'are', 'you', 'doin'], 3)
['Hello', 'doin']