Method to dictionary key - python

In this example I want to do a menu with commands (add 2 numbers and sub 2 numbers). I would like to do this with a dictionary where I want to assign to the key value the method add and sub. When I call the method UI,the key values are called. How to fix it?
class Calc():
def __init__(self):
pass
def add(self):
a = int(input("Number a is:"))
b = int(input("Number b is:"))
return a + b
def sub(self):
a = int(input("Number a is:"))
b = int(input("Number b is:"))
return a + b
def UI(self):
Options = {1:self.add(), 2:self.sub()}
n = Calc()
n.UI()

I would recommend not adding function calls to dict's as it will likely just add confusion to your code. However if you have to do it that way you can store the pointers to the functions.
Options = {1:self.add,
2:self.sub
}
Which can than be called like
Options1
A quick working example based on your original code:
class Calc():
def __init__(self):
pass
def add(self):
a = int(input("Number a is:"))
b = int(input("Number b is:"))
return a + b
def sub(self):
a = int(input("Number a is:"))
b = int(input("Number b is:"))
return a + b
def UI(self, option):
Options = {1:self.add,
2:self.sub
}
return Options[option]()
n = Calc()
n.UI(1)
Number a is:1
Number b is:1
2

The code:
Options = {1:self.add(),
2:self.sub()
}
actually calls the add and sub methods once when the dictionary is created. You want the methods to be called when the user selects an option from the menu. You could do it with this as your UI() method instead:
def UI(self):
options = {1:self.add,
2:self.sub}
while True:
# get user selection
selection = input("1. add\n2: subtract\nSelection: ")
if selection.lower().startswith('q'):
# any input starting with "Q" or "q" quits
break
# call method corresponding to the user's selection
result = options[int(selection)]()
# error handling omitted
print("Result: {}".format(result))
P.S. your sub() method actually adds.
Update
You now require that the parameters for the various operations be passed to the method. This means that the parameters must be collected externally to the method. Here is one such way:
import operator
class Calc:
def my_div(self, a, b):
return a / float(b) # ensure float division
def UI(self):
options = {1: operator.add,
2: operator.sub,
3: self.my_div,}
while True:
# get user selection
selection = input("1. add\n2: subtract\n3: divide\nq: quit\nSelection: ")
if selection.lower().startswith('q'):
# any input starting with "Q" or "q" quits
break
selection = int(selection)
if selection not in options:
print("Invalid selection, try again")
continue
# get arguments to pass to operation
a = int(input("Number a is:"))
b = int(input("Number b is:"))
# call method corresponding to the user's selection
result = options[selection](a, b)
# error handling omitted
print("Result: {}".format(result))
It's optional, but you no longer need to define your own add(), sub(), etc. methods. You can simply use those provided by the operator module as shown above, or you can implement your own also as shown above.
This assumes that all operations require the same number of arguments. If that is not the case then you could set your dictionary to contain tuples with the function and required number of arguments:
options = {1: (operator.add, 2),
2: (operator.sub, 2),
3: (self.my_div, 2),
4: (operator.neg, 1), # N.B. unary operator
}
Then, when you get the arguments from the user:
# get arguments to pass to operation
function, n_args = options[selection]
args = [int(input("Number {} is:".format(i+1))) for i in range(n_args)]
Finally, call the method:
result = function(*args)
which will unpack the arguments and pass them into the corresponding function.

First you need to change your dictionary to something like this:
options = {1:self.add, 2:self.sub}
so python does not call the methods when the dict is crated, but stores the method reference in options as values.
Now you can call (ie. execute) a method in options by calling
options[some_key]()
or (as you wanted)
options[1]() #add
options[2]() #sub

Related

Python OPC UA pass variables to uamethod

I have an example where a method is being added to the server space. The example is set up to take two input values and add them together.
Code example
from opcua import Server, ua, uamethod, instantiate
import time
from opcua.ua import NodeId, NodeIdType
#uamethod
def add_func(self, a, b):
print("Adding parameters:\n", a, "\tand\t", b)
return a + b
if __name__ == "__main__":
# setup server
server = Server()
server.set_endpoint("opc.tcp://localhost:4840") #alternative:
server.set_endpoint("opc.tcp://0.0.0.0:4840")
server.set_server_name("Server example")
server.set_security_policy([ua.SecurityPolicyType.NoSecurity])
uri = "http://example.uri.de"
idx = server.register_namespace(uri)
# get Objects node, this is where we should adress our custom stuff to
objects = server.get_objects_node() # alternative: root_node = server.get_root_node()
# add structure to the namespace (idx) below the Objects node
myobj = objects.add_object(idx, "MyObject")
# add variables, type can be defined by assigning a value or ua Variant Type definition
var1 = myobj.add_variable(idx, "var1", 321, ua.VariantType.Int64)
var2 = myobj.add_variable(idx, "var2", 123, ua.VariantType.Int64)
# set variables writable for clients (e.g. UaExpert)
var1.set_writable()
var2.set_writable()
# set input arguments for method
input_arg1 = ua.Argument() # create new argument
input_arg1.Name = "a" # name for argument
input_arg1.DataType = ua.NodeId(ua.ObjectIds.Int64) # data type
input_arg1.ValueRank = -1 # value rank to be treated a scalar number
input_arg1.Description = ua.LocalizedText("First integer a") # add description text
input_arg2 = ua.Argument()
input_arg2.Name = "b"
input_arg2.DataType = ua.NodeId(ua.ObjectIds.Int64)
input_arg2.ValueRank = -1
input_arg2.Description = ua.LocalizedText("Second integer b")
# set output arguments
output_arg = ua.Argument()
output_arg.Name = "Result"
output_arg.DataType = ua.NodeId(ua.ObjectIds.Int64)
output_arg.ValueRank = -1
output_arg.Description = ua.LocalizedText("Sum")
print(var1.nodeid)
print(var2.nodeid)
# add method to namespace
mymethod = myobj.add_method(idx, "MyAddFunction", add_func, [input_arg1, input_arg2], [output_arg])
server.start()
The change I want to make is to remove the input arguments and automatically take var1 & var2 as input when calling MyAddFunction.
I use UaExpert to call this method.
UaExpert when calling MyAddFunction
I've tried to pass the variables by using their NodeID like this:
mymethod = myobj.add_method(idx, "MyAddFunction", add_func, [var1.nodeid, var1.nodeid], [output_arg])
and get following error message:
opcua.ua.uaerrors._base.UaError: NodeId: Could not guess type of NodeId, set NodeIdType
Is the type not defined when creating the variables?
What changes have to made for the method to take var1 & var2 as input argument? is there a way to assign these values to the created input arguments (input_arg1 & input_arg2)?
Thank you in advance!
regards Nando

Python variable's value doesn't get changed outside the function

I'm working on a school project. I made a test version of my program, because I'm new to Python and I only have experience with C#, so I'm still learning te basics. My problem is the following:
Before the function "Fill_Array()" I declared a variable (" max_element_var") that is supposed to store the max number of elements that can be stored in the array ("content_array"). Later in the function I change it's value to the input of the console, which happens, and the function runs as it should, the only problem being is that outside the function the value of " max_element_var" stays "None". What should I do in order to fix this?
#__Test__#
def Test():
class Que:
def __init__(self, content, max_element ,actual_elements):
self.content = content
self.max_element = max_element
self.actual_elements = actual_elements
max_element_var = None
content_array = []
def Fill_array():
print("What should be the max number of elements that can be stored in the array? (Type in an integer!)")
max_element_var = int(input())
if(max_element_var>0):
import random
random_var = random.randrange(0,max_element_var)
for x in range(max_element_var-random_var):
content_array.append(x)
else:
print("It has to be more than 0!")
Fill_array()
Fill_array()
actual_elements_var = len(content_array)
que = Que (content_array, max_element_var, actual_elements_var)
print("Content: ", que.content)
print("Max number of elements: ", que.max_element)
print("Actual number of elements: ", que.actual_elements)
#__Test__#
#__Full__#
def Full():
pass
#__Full__#
#__Version_selector__#
def Version_selector():
print("Which version should be used? (Type in the number!)")
print("1 - Test")
print("2 - Full")
answer = int(input())
if(answer == 1):
Test()
Version_selector()
elif(answer == 2):
Full()
Version_selector()
#__Version_selector__#
Version_selector()
In python variables are automatically created as local, in the scope of the function which used them alone.
To solve your problem you may either
(1) return the variable, passing it from one function the other explicitly.
(2) declare it as global so all functions have access to it.
More about scopes here and here.
Consider the following code. In the code below you persumably change the value of x but in fact there is a big difference between the x inside the function and outside. The x inside the function is a local variable and will "disappear" once the function ends. If you want to save the value of x you must use return x and save the outcome to a variable. For example, See the function a_saving_example(x)
you may also use a global variable though some say it is bad practice and it is better to use return in your function.
def times_two(x):
x = x * 2
x = 5
print(x)
times_two(x)
print(x)
output:
5
5
saving example:
def a_saving_example(x):
x = x * 2
return x
x = 5
print(x)
x = a_saving_example(x)
print(x)
output:
5
10
Modified code to correct some issues.
Import normally done at top of module (not within functions)
Remove nested class definition inside function (obfuscates things in simple code)
Changed recursive calls to a while loop (a better way to repeat execution of a function from beginning in Python since no tail recursion).
Code Refactoring
import random
class Que:
def __init__(self, content, max_element ,actual_elements):
self.content = content
self.max_element = max_element
self.actual_elements = actual_elements
def Fill_array():
" Returns requested size and array "
while True:
prompt = """"What should be the max number of elements that can be stored in the array? Type in an integer!: """
max_element_var = int(input(prompt))
if max_element_var > 0:
random_var = random.randrange(0,max_element_var)
return max_element_var, [x for x in range(max_element_var-random_var)]
else:
print("It has to be more than 0!")
def Test():
max_element_var, content_array = Fill_array()
actual_elements_var = len(content_array)
que = Que (content_array, max_element_var, actual_elements_var)
print("Content: ", que.content)
print("Max number of elements: ", que.max_element)
print("Actual number of elements: ", que.actual_elements)
#__Test__#
#__Full__#
def Full():
pass
#__Full__#
#__Version_selector__#
def Version_selector():
while True:
prompt = """Which version should be used? (Type in the number!)
1 - Test
2 - Full
3 - Quit\n\t"""
answer = int(input(prompt))
if answer == 1:
Test()
elif answer == 2:
Full()
else:
break
#__Version_selector__#
Version_selector()

How to use a Python class and ask for user input? [duplicate]

This question already has answers here:
TypeError: Missing 1 required positional argument: 'self'
(8 answers)
Closed 6 months ago.
This is my first attempt at creating and using a class. The error is occurring when I ask the user for input. I'm getting the following error:
n1 = Arithmetic.float_input("Enter your First number: ")
TypeError: float_input() missing 1 required positional argument: 'msg'
Here is my code.
# Define class
class Arithmetic:
def float_input(self, msg): # Use this function for exception handling during user input
while True:
try:
return float(input(msg))
except ValueError:
print("You must enter a number!")
else:
break
def add(self, n1, n2):
sum1 = n1 + n2
print(n1,"+" ,n2,"=", sum1)
def sub(self, n1, n2):
diff = n1 - n2
print(n1,"-",n2,"-", diff)
def mult(self, n1, n2):
product = n1 * n2
print(n1,"*",n2, "=", product)
def div(self, n1, n2):
if n2 == 0:
print(n1, "/",n2,"= You cannot divide by Zero")
else:
quotient = n1 / n2
print(n1, "/",n2,"=", quotient)
def allInOne(self, n1, n2):
#Store values in dictionary (not required, just excercising dictionary skill)
res = {"add": add(n1, n2), "sub": sub(n1, n2), "mult": mult(n1, n2), "div": div(n1, n2)}
# Declare variables. Ask user for input and use the exception handling function
n1 = Arithmetic.float_input("Enter your First number: ")
n2 = Arithmetic.float_input("Enter your Second number: ")
What am I missing?
If you're coming from a Java background, it's worth knowing you really usually don't need to wrap methods in classes in Python unless you need state provided by self.
Anyway, the error you're seeing is because your methods aren't marked #classmethod or #staticmethod and thus require an instance of the class and you're just calling them via the class itself (so no implicit instance or class object is passed in as the first parameter).
Thus your options are:
1 – create an instance of Arithmetic() and use it:
arith = Arithmetic()
n1 = arith.float_input("Enter your First number: ")
n2 = arith.float_input("Enter your Second number: ")
2 – mark the methods static, e.g.
#staticmethod
def float_input(prompt): # note: no `self`
3 – mark the methods classmethods, e.g.
#classmethod
def float_input(cls, prompt): # `cls` is `Arithmetic` (or its subclass) itself
4 – make the methods just regular functions without a class.
The problem is that you did not create an instance of Arithmetic before calling the method. Because you did not create an object, no instances will be passed to the self parameter. This causes the message "Enter your first number:" to be passed to the self parameter and the msg parameter to be empty.
To fix the problem, simply create an object using parentheses after the class name, example:
# Declare variables. Ask user for input and use the exception handling function
n1 = Arithmetic().float_input("Enter your First number: ")
n2 = Arithmetic().float_input("Enter your Second number: ")
If you did not create an object on purpose, you can use the #classmethod class decorator to pass the class name to the self parameter.
# Define class
class Arithmetic:
#classmethod
def float_input(class_, msg): # Use this function for exception handling during user input
while True:
try:
return float(input(msg))
except ValueError:
print("You must enter a number!")
else:
break
# Code...
n1 = Arithmetic.float_input("Enter your First number: ")
n2 = Arithmetic.float_input("Enter your Second number: ")
There is also another decorator named #staticmethod. If you use this decorator, you can call the method without having an instance of Arithmetic and without having to define self in the method signature. Example:
class Arithmetic:
#staticmethod
def float_input(msg): # Use this function for exception handling during user input
while True:
try:
return float(input(msg))
except ValueError:
print("You must enter a number!")
else:
break
# Code...
n1 = Arithmetic.float_input("Enter your First number: ")
n2 = Arithmetic.float_input("Enter your Second number: ")
fix as:
# Declare variables. Ask user for input and use the exception handling function
arithmatic = Arithmetic()
n1 = arithmatic.float_input("Enter your First number: ")
n2 = arithmatic.float_input("Enter your Second number: ")
its better to instantiate the class first, and then use the proper method of it, like below
n1 = new Arithmetic()
n1.float_input('Enter your First number: ')

Def return in class as second, third argument for Class

I am creating a class to make some calculations. The class would have 3 arguments to get started. I have done like this in a simplified representation:
class TheCalcs:
def __init__(self, pk_from_db, cat_score_list, final_score):
self.pk_from_db = pk_from_db
self.cat_score_list = cat_score_list
self.final_score = final_score
def calculate_cat_score(self):
#Do some calcs with the data of the pk_from_db and return that!
a_list_of_scores = [] # create a list of scores
return a_list_of_scores
def final_score(self): # The argument for this function would be the return of the calculate_cat_score function!
# Again do some calcs and return the final score
the_final_score = int()
return the_final_score
def score_grade(self): # the argument this this function again the return but now from the final_score function
# Do some cals and return the grade
the_grade = ("a string", "an integer")
return the_grade
When I call the class I would have to present the arguments --> However as you can see I just do now the value of the first argument. The second and the third being calculated throughout the class. When I call the class just with one argument I will of course have an error of failing arguments. Anyone has an idea on that?
If those values are calculated, simply don't make them arguments. You could instead call those calculation methods to compute the values:
class TheCalcs:
def __init__(self, pk_from_db):
self.pk_from_db = pk_from_db
self.cat_score_list = self.calculate_cat_score()
self.final_score = self.calculate_final_score()
# ...
or postpone calculations until you need them.

Feedback tester python

Hi for a given function I have 2 parameters which are string and an Int but I don't know which comes first. So I have a function "pick_type()" that tries to guess the order of the parameters. So my question is when "pick_type()" incorrectly guesses the order, how do I record this and make sure "pick_type()" never tries that specific order again ?
for iteration in range(0, 10):
args = []
print("\n def test%d(self):" % (iteration))
for input in range(num_arguments):
args += pick_type()
try:
result = target(*args)
code = test_to_string(target, args, result)
except TypeError as error:
code = test_to_string_exc(target, args, error)
for line in code.splitlines():
print(" "+line)
def pick_type():
lista = []
words = ['rhythms', 'rhythms', 'manager', 'training', 'hotel', 'destroy']
word = choice(words)
num = random.randint(-100, 100)
lists = [word,num]
choices = choice(lists)
if choices == word:
lista.append(word)
else:
lista.append(num)
return lista
I would suggest wrapping your method in a class, then you can have a persistent list of bad orders. It's not clear to me what you mean by an "order", but whatever it is, hopefully this pseudo-code helps:
class PickType:
def __init__(self):
self._bad_orders = []
def pick_type(self):
...# insert body here
if order in self._bad_orders:
## pick another order
## test the new order
if <order is bad>:
self._bad_orders.append(order)
## if your test for bad orders is performed outside pick_type(), you just need a method to add to the list of bad_orders
def add_bad_order(self, order):
self._bad_orders.append(order)

Categories

Resources