Function handle to a built-in operator in Python - python

Given the following minimal snippet of code:
def cmp(a, b, cmp):
return cmp(a, b)
a = 1
b = 2
print(cmp(a, b, operator.__eq__))
I'd just like to give a built-in operator like == or > as a function handle into a function. This would be useful for example, if comparisons all need some pre-checks.
The last line gives an error, as it does not know operator.__eq__. How do I correctly name (and import) that == operator on that line?

Just add import operator and the code is working.
import operator
def cmp(a, b, _cmp):
return _cmp(a, b)
a = 1
b = 2
print(cmp(a, b, operator.__eq__))
I have renamed the function parameter for clarity.

Related

How would I run a function given its name?

I have a large number of blending functions:
mix(a, b)
add(a, b)
sub(a, b)
xor(a, b)
...
These functions all take the same inputs and provide different outputs, all of the same type.
However, I do not know which function must be run until runtime.
How would I go about implementing this behavior?
Example code:
def add(a, b):
return a + b
def mix(a, b):
return a * b
# Required blend -> decided by other code
blend_name = "add"
a = input("Some input")
b = input("Some other input")
result = run(add, a, b) # I need a run function
I have looked online, but most searches lead to either running functions from the console, or how to define a function.
I'm not really big fan of using dictionary in this case so here is my approach using getattr. although technically its almost the same thing and principle is also almost the same, code looks cleaner for me at least
class operators():
def add(self, a, b):
return (a + b)
def mix(self, a, b):
return(a * b)
# Required blend -> decided by other code
blend_name = "add"
a = input("Some input")
b = input("Some other input")
method = getattr(operators, blend_name)
result = method(operators, a, b)
print(result) #prints 12 for input 1 and 2 for obvious reasons
EDIT
this is edited code without getattr and it looks way cleaner. so you can make this class the module and import as needed, also adding new operators are easy peasy, without caring to add an operator in two places (in the case of using dictionary to store functions as a key/value)
class operators():
def add(self, a, b):
return (a + b)
def mix(self, a, b):
return(a * b)
def calculate(self, blend_name, a, b):
return(operators.__dict__[blend_name](self, a, b))
# Required blend -> decided by other code
oper = operators()
blend_name = "add"
a = input("Some input")
b = input("Some other input")
result = oper.calculate(blend_name, a, b)
print(result)
You can create a dictionary that maps the function names to their function objects and use that to call them. For example:
functions = {"add": add, "sub": sub} # and so on
func = functions[blend_name]
result = func(a, b)
Or, a little more compact, but perhaps less readable:
result = functions[blend_name](a, b)
You could use the globals() dictionary for the module.
result = globals()[blend_name](a, b)
It would be prudent to add some validation for the values of blend_name

Reference first value in ternary operator

Very often I find myself writing a ternary operator equivalent to the following
var = a if returnsBool(a) else b
with returnsBool returning a boolean value depending on the value of a.
When a is lengthier variable it starts to look ugly and 'unpythonic'. Is there a way to reference a in the conditional part (returnsBool(a)) of the statement so you don't have to write a twice?
Or is there a better approach for this case, which is also useful for list comprehensions?
You can use the := "walrus" assignment operator that was introduced in Python 3.8:
def returnsBool(a):
return bool(a)
reallylengthiervariablename = 42
b = 2
var = a if returnsBool(a := reallylengthiervariablename) else b
print(f'{var=}') # -> var=42
As long as a itself cannot be a "falsy" value, you could change your returnsBool to return a / None instead of True / False.
Then you could write:
var = maybe(a) or b
Otherwise, defining your own ternary seems like the best bet:
def conditional(func, a, b):
return a if func(a) else b
And you could customize it for specific conditions using partial:
from functools import partial
some_cond = partial(conditional, returnsBool)
vars = [some_cond(a, b) for a, b in whatever]
Here's a not-very-idiomatic way of doing it, but it works; the next function can take a second argument which is returned in case the first argument is an empty iterator.
>>> def is_even(x): return x % 2 == 0
...
>>> very_long_variable_name = 12
>>> next(filter(is_even, [very_long_variable_name]), 'default')
12
>>> very_long_variable_name = 13
>>> next(filter(is_even, [very_long_variable_name]), 'default')
'default'
If you find yourself having to do this often, it may be worth writing a helper function, so that you can write e.g. if_else(is_even, very_long_variable_name, 'default').
def if_else(predicate, a, b):
return a if predicate(a) else b

Function as an argument of another function

I'm learning this language hence I'm new with Python. The code is:
def add(a, b):
return a + b
def double_add(x, a, b):
return x(x(a, b), x(a, b))
a = 4
b = 5
print(double_add(add, a, b))
The add function is simple, it adds two numbers. The double_add function has three arguments. I understand what is happening (With some doubts). The result is 18. I can't understand how double_add uses add to function.
The question is, what is the connection between these two functions?
It would be helpful if tell me some examples of using a function as an argument of another function.
Thanks in advance.
In python language, functions (and methods) are first class objects. First Class objects are those objects, which can be handled uniformly.
So, you just pass a method as an argument.
Your method will return add(add(4, 5), add(4, 5)) which is add(9, 9) and it's equals to 18.
A function is an object just like any other in Python. So you can pass it as argument, assign attributes to it, and well maybe most importantely - call it. We can look at a simpler example to understand how passing a function works:
def add(a, b):
return a + b
def sub(a, b):
return a - b
def operate(func, a, b):
return func(a, b)
a = 4
b = 5
print(operate(add, a, b))
print(operate(sub, a, b))
operate(print, a, b)
And this prints out:
9
-1
4 5
That is because in each case, func is assigned with the respective function object passed as an argument, and then by doing func(a, b) it actually calls that function on the given arguments.
So what happens with your line:
return x(x(a, b), x(a, b))
is first both x(a, b) are evaluated as add(4, 5) which gives 9. And then the outer x(...) is evaluated as add(9, 9) which gives 18.
If you would add print(x) in the double_add function you would see that it would print <function add at 0x10dd12290>.
Therefore, the code of double_add is basically the same as if you would do following:
print(add(add(a,b), add(a,b))) # returns 18 in your case
Functions are objects in Python, just like anything else such as lists, strings.. and you can pass them same way you do with variables.
The function object add is passed as an argument to double_add, where it is locally referred to as x. x is then called on each, and then on the two return values from that.
def double_add(x, a, b):
return x(x(a, b), x(a, b))
Let's write it differently so it's easier to explain:
def double_add(x, a, b):
result1 = x(a, b)
result2 = x(a, b)
return x(result1, result2)
This means, take the function x, and apply it to the parameters a and b. x could be whatever function here.
print(double_add(add, a, b))
Then this means: call the double_add function, giving itaddas the first parameter. Sodouble_add`, would do:
result1 = add(a, b)
result2 = add(a, b)
return add(result1, result2)
This is a very simple example of what is called "dependency injection". What it means is that you are not explicitly defining an interaction between the two functions, instead you are defining that double_add should use some function, but it only knows what it is when the code is actually run. (At runtime you are injecting the depedency on a specific function, instead of hardcoding it in the function itself),
Try for example the following
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def double_add(x, a, b):
return x(x(a, b), x(a, b))
a = 4
b = 5
print(double_add(add, a, b))
print(double_add(subtract, a, b))
In other words, double_add has become a generic function that will execute whatever you give it twice and print the result

How can you take a function as a parameter and call it?

My task is the following: "Write a function named operate that takes as parameters 2 integers named a, b and a function named func which that takes 2 integers as parameters. Also write the functions add, sub, mul, and div that take 2 integer parameters and perform the operation corresponding to their name and print the result. Calling operate(a, b, func) should result in a call to func(a, b)". I've done the first four parts, but I'm stuck on how to implement operate. Here is my code so far:
# this adds two numbers given
def add(a,b):
print (a + b)
# this subtracts two numbers given
def sub(a,b):
print (b - a)
# this multiplies two numbers given
def mul(a,b):
print (a * b)
# this divides two numbers given
def div(a,b):
print (a / b)
To achieve this you need to return something from your functions, not just print something. This lets you use the result later. To do this just use the return statement with some expression:
def add(a, b):
return a + b
def sub(a, b):
return a - b
def mul(a, b):
return a * b
def div(a, b):
return a / b
I've changed the order of your sub operation to be more in line with how subtraction is generally defined.
To now write an operate function is actually pretty easy. You've been given two parts already: the signature should be operate(a, b, func) and you should call func(a, b). This is actually almost all of what it will end up as - all you need to do is again return it (you could also print it here if you wanted):
def operate(a, b, func):
return func(a, b)
You can now do something like this:
print(operate(3, 2, add))
print(operate(3, 2, sub))
print(operate(3, 2, mul))
print(operate(3, 2, div))
Which will result in the output:
5
1
6
1.5
In a comments I asked about the standard library - you see, all of these are already implemented by Python. You can replace the first four function definitions with this:
from operator import add, sub, mul, truediv as div
Leaving you to only define operate and do some testing.

Overload python ternary operator

Is it possible to overload the ternary operator in python? Basically what I want is something like:
class A(object):
def __ternary__(self, a, c):
return a + c
a = A()
print "asdf" if a else "fdsa" # prints "asdffdsa"
I'm trying to implement a symbolic package and basically want something that can do things like:
sym = Symbol("s")
result = 1 if sym < 3 else 10
print result.evaluate(sym=2) # prints 1
print result.evaluate(sym=4) # prints 10
Edit: Let me put out a bit more complex example to show how this could be layered upon.
sym = Symbol("s")
result = 1 if sym < 3 else 10
...
something_else = (result+1)*3.5
...
my_other_thing = sqrt(something_else)
print my_other_thing.evaluate(sym=2) # prints sqrt(7) or rather the decimal equivalent
The point is, I don't need to just be able to late evaluate the one ternary operator, I need to take the result and do other symbolic stuff with that before finally evaluating. Furthermore, my code can do partial evaluations where I give it a few bindings and it returns another symbolic expression if it can't evaluate the full expression.
My backup plan is just to directly use the ternary class taking 3 expressions objects that I would need to make anyway. I was just trying to hide the generation of this class with an operator overload. Basically:
a = TernaryOperator(a,b,c)
# vs
b = a if b else c
look at the sympy module; it already does this
for simple comparison, write A.__eq__ and A.__lt__ methods and use the total_ordering class decorator; this should be sufficient for comparing two As or an A and a constant
write it as a lambda,
result = lambda sym: 1 if sym < 3 else 10
print(result(2)) # => 1
print(result(4)) # => 10
Overload the comparison operators instead (something you probably needed to do anyway):
class A(object):
def __lt__(self, other):
return self.value() < other.value() # Replace with your own implementation of <
Then, use lambda functions to achieve the delayed evaluation you desire:
sym = Symbol("s")
result = lambda s: 1 if s < 3 else 10
sym.set(2)
print result(sym) # prints 1
sym.set(4)
print result(sym) # prints 10
(I don't think you can overload the assignment operator, as it doesn't actually perform an operation on any object, but rather on a variable.)

Categories