Can you use a variable to call a function [duplicate] - python

This question already has answers here:
Construct callable function from string [duplicate]
(3 answers)
Closed 12 months ago.
I have four subroutines to multiply, divide, add and subtract 2 numbers which I will ask the user for.
My unfinished code is:
def multiply(a, b):
print(f"{a} x {b} = {a*b}")
def divide(a, b):
print(f"{a} รท {b} = {a*b}")
num1 = int(input("What is the first number?\n"))
num2 = int(input("What is the second number?\n"))
calculation = input("What calculation would you like to perform? [multiply, divide]\n")
calculation(num1, num2)
but it gives TypeError: 'str' object is not callable
Is it necessary to use if statements like:
if calculation == 'multiply':
multiply()
elif calculation == 'divide':
divide()
for all four subroutines or can I use the variable calculation to substitute for the function name.

Use a dictionary to hold your functions
funcs = {'multiply': multiply, 'divide': divide}
and then access funcs[calculation].
... or if you have a DRY fetish:
funcs = {f.__name__: f for f in [multiply, divide]}
Demo:
>>> funcs['multiply'](3, 4)
3 x 4 = 12
You could also access the globals() dict
>>> globals()['multiply'](3, 4)
3 x 4 = 12
but this is not such a good idea because the function to call comes from user input and who knows what weird callables are in globals().
Bonus: safeguarding against bad input
from functools import partial
def notfound(fname, *_, **__):
print(f'function {fname!r} not found')
Usage:
>>> calculation = 'multiply'
>>> funcs.get(calculation, partial(notfound, calculation))(3, 4)
3 x 4 = 12
>>> calculation = 'none'
>>> funcs.get(calculation, partial(notfound, calculation))(3, 4)
function 'none' not found

Related

<function output at 0x> when calling function [duplicate]

This question already has an answer here:
Python <function at 0x> output [duplicate]
(1 answer)
Closed 3 years ago.
def num(num1, num2):
def adder(num):
return (num1 + num2)
return adder()
num(5, 6)
When I type this code in i get the output of < function num..adder at 0x10b83bdd0 >, and I'm not entirely sure what I'm doing wrong. How do I get it to return 11?
num returns a function, so you need to call it:
num(5, 6)(0) # the number you call it with is irrelevant since you never use num in adder
# 11
In this case this approach is kind of useless. This is usually done if you want to define a partial function or a "function factory", for example:
def multiplier(multiply_by):
def inner(n):
return multiply_by * n
return inner
multiply_by_2 = multiplier(2)
multiply_by_4 = multiplier(4)
print(multiply_by_2(4))
print(multiply_by_4(4))
Outputs
8
16
Your example would have made more sense if the argument was actually used in the inner function, then this becomes very similar to my example above but using addition instead of multiplication:
def adder(num1):
def inner(num2):
return num1 + num2
return inner
two_adder = adder(2)
three_adder = adder(3)
print(two_adder(2))
print(three_adder(2))
Outputs
4
5
You return the adder function, but you don't call it.
The function returns another function. If you want a number, you need to call the returned function as well:
f = adder(1, 2)
print(f(4)) # Call the returned f
Although the second call is useless since you never make use of num.

Converting a method with 2 variables to one variable [duplicate]

This question already has answers here:
Pass a function as a variable with one input fixed
(4 answers)
Closed 5 years ago.
I have a function foo that takes 2 arguments a and b. I want to create a list of functions that are similar to foo, but value of a is fixed.
def foo(a,b):
return a*b
fooList = []
for i in range(n):
fooList.append(foo(i))
I want fooList[i] to return a function that is similar to foo(i, b).
You can use functools.partial:
from functools import partial
def foo(a, b):
return a * b
fooList = []
for i in range(n):
fooList.append(partial(foo, i))
Then you'd do fooList[i](5) to calculate i * 5.
You can also curry lambda functions, somewhat like this:
for i in range(n):
fooList.append((lambda x: lambda y: x * y)(i))
You can then call that the same way as above.

How to create an output out of a given operand and values in Python?

So I'm creating a program that gives random outputs including addition, subtraction, multiplication and division. In order to remove repeating any code I am attempting to narrow the function down to essentially
sum(operand)
a = random.randint(1, 10)
b = random.randint(1, 10)
c = a + operand + b
print c
I am looking to be able to call say sum(*) so c would return the product of a and b.
I feel like this is a concatenation issue
Here I am using sum as an arbitrary name. The function should be able to add, subtract, multiply and divide, all depending on the operand passed through. For example, if "-" is passed through, c would be a - b, if "/" was passed through, c would be a / b
Thanks
import random
def operate(a, b, operand):
return eval(str(a) + operand + str(b))
"operand" is a string.
operate(50,5,"*") would return 250, for example.
The eval() function takes a string and executes it. This converts a and b to strings, so in the example given, the resulting string would be "50*5", which would then be executed by eval().
Python:: Turn string into operator
This question basicially asks the same allthough with a different starting point.
From the accepted answer by Annon:
import operator
ops = { "+": operator.add, "-": operator.sub } # etc.
print ops["+"](1,1) # prints 2
Reference to imported operator class:
https://docs.python.org/3.6/library/operator.html
You can try this:
import random
def produce(func):
a = random.randint(1, 10)
b = random.randint(1, 10)
c = func(a,b)
return c
def sum(a,b):
return a+b
def multiply(a,b):
return a*b
def substract(a,b):
return a-b
operands = [
sum,
multiply,
substract,
]
# tests
print "\n".join(["%s: %d" % ( op.__name__, produce(op) ) for op in operands ])
Sample output:
sum: 14
multiply: 45
substract: 7
Unified solution (for int numbers, as example) emulating numeric objects and calling __add__, __sub__, __mul__ and floordiv methods:
def do_arith_operation(a, b, op):
a = int(a).__int__()
b = int(b).__int__()
operators = {'+': '__add__', '-': '__sub__', '*': '__mul__', '/': '__floordiv__'}
return getattr(a, operators[op])(b)
print(do_arith_operation(10, 2, '/'))
The output:
5
int(a).__int__() will create an instance of class <class 'int'>
__add__, __sub__, __mul__ and floordiv methods:
each method takes two objects (the operands of +|-|*|/|) as arguments and returns the result of computation
https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

Complex number in python

How to write a complex number in python? Indeed I have:
import math
a=3
b=4
function=a*j*x+b*y
I don't want to write directly 3j in my function since I absolutely want to use a, so how to convert a into a complex number? Cause in matlab it works when printing :
a=3
b=a*i
The result will gave: 0 + 3.0000i
Thank you for your answers.
j alone is a variable, you can have the complex number by typing 1j
>>> type(j)
NameError: name 'j' is not defined
>>> type(1j)
<type 'complex'>
So your code can be written as a function as
def function(x, y):
a = 3
b = 4
return a*1j*x+b*y
You can use the complex function to create a complex number from variables:
>>> a = 3
>>> b = 4
>>> complex(a, b)
(3+4j)
You can simply use Python's Built in complex() function
>>> first_number = 10
>>> second_number = 15
>>> complex(first_number, second_number)
(10+15j)

Why function which takes arguments cannot callable in iterator?

There are two examples.
# 1st example
>>> def accum(sum, a):
return sum + a
>>> sum = 0
>>> for sum in iter(lambda:accum(sum, 2), 40):
print sum,
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32...
# 2nd example
>>> def accum(sum, a):
return sum + a
>>> sum = 0
>>> for sum in iter(accum(sum, 2), 40):
print sum,
TypeError: iter(v, w) : v must be callable
Why lambda function doesn't make error but accum function makes error?
Thanks in advance :)
In neither case you are passing a function that takes arguments. In second case the value of v is bound to the integer 2, whereas in the first case v refers to a callable anonymous lambda function () -> sum + a.
The following 2 are almost equivalent:
def x():
return sum + a
x = lambda: sum + a
except lambda does not provide nice debugging traceback, since lambda functions are unnamed.
Also, the names of the variables are a bit misleading, took me a some moments to figure out what is happening. There are exactly 2 variables called sum - the one within accum function, and the other in the global scope. There is also the 3rd, masked one that contains the global built-in function sum...
The lambda is an anonymous function and is callable. If the notation is confusing, you can replace it with a named function:
def wrapper():
return accum(sum, 2)
for sum in iter(wrapper, 40):
The v argument must be callable. The result of accum(sum, 2) is an integer, which isn't callable.

Categories