Python - use an operator at runtime - python

Is it possible to insert an operation (e.g *, +) between two variables at runtime?
My solution without doing this is multiple if, elif statements, but I don't think that's the most efficient way to do it.
EDIT: What I meant is I get two integers, and I want to apply an operation on one of them with the other, e.g x * y, but I want to change * to another operator (maybe they're called functions? Not sure) e.g -, +,^ based on input.
Does that make sense? Basically think of it as a calculator.

I'm not sure if this is what you're looking for but the operator module has a lot of operations, e.g. add and mul (multiply):
import operator
var_1 = 2
var_2 = 3
print(operator.add(var_1, var_2))
print(operator.mul(var_1, var_2))
will print
5
6

#AaronHall's is the answer you're looking for, but for completeness, I'd mention you can also use eval.
var_1 = 2
var_2 = 3
op = '+'
print eval('%s%s%s' % (var_1, op, var_2))
However, eval is evil, so either don't use it, or use with caution.

To answer the follow-on question, for example, you can subclass int and then implement __xor__ to exponentiate instead of apply a bitwise or, which is called by the ^ operator:
import operator
class MyInt(int):
def __xor__(self, other):
return operator.pow(self, other)
and then:
>>> i = MyInt(2)
>>> i
2
>>> type(i)
<class '__main__.MyInt'>
>>> j = 3
>>> i^j
8

If your list of operators is small enough you can probably use lambdas.
def operator_factory(op):
if op == '+':
return lambda x,y: x + y
elif op == '-':
return lambda x,y: x - y
elif op == '*':
return lambda x,y: x * y
elif op == '/':
return lambda x,y: x / y
elif op == '^':
return lambda x,y: x ^ y
Your if statements can depend on user input. Then you just use this like so:
>>> f = operator_factory('+')
>>> f(2,3)
5

Related

Python: Comparison in function argument

I am currently working on the following problem:
I want to write a function, that accepts comparisons as arguments - but want to prevent, that these comparisons are evaluated during runtime (leading to potentially unexpected results).
To be more precise, I have the following challenge (first, original one in pySpark, then similar, more general one):
def test_func(*comparisons):
for comparison in comparison:
left_hand = comparison[0]
comparison = comparison[1]
right_hand = comparison[2]
Example 1:
test_func(F.col('a') == F.col('b'))
left_hand -> F.col('a')
right_hand -> F.col('b')
comparison -> ==
Example 2:
test_func(1 <=> 2)
left_hand -> 1
right_hand -> 2
comparison -> <=>
Right now, the equation/parameter is evaluated before it reaches the function - i.e., I have problems splitting the equation into it individual parts.
Is this even possible to like this?
The python operator module stores operators as functions
from operator import *
def test_func(*comparison):
left_hand = comparison[0]
comparison = comparison[1]
right_hand = comparison[2]
test_func(F.col('a'), eq, F.col('b'))
The variables would be (remember they would still be local to test_func):
left_hand = F.col('a')
comparison = eq -> operator.eq
right_hand = F.col('b')
As a quick proof of concept:
>>> import operator
>>> class Col:
... def __init__(self, col):
... self.col = col
...
... def __eq__(self, other):
... return self, operator.eq, other
...
>>> Col('a') == Col('b')
(<__main__.Col object at 0x11134d5b0>, <built-in function eq>, <__main__.Col object at 0x11147cbe0>)
>>> lh, comp, rh = Col('a') == Col('b')
>>> comp(lh.col, rh.col)
False
You'll need to overload all special methods for all operators you want to support, and return the equivalent operator function (or whatever you want, perhaps '==', or a custom object).

Python: Haskell-like . / $

In Haskell I would write:
main = do mapM_ print . map (\x -> x^2) . filter (\x -> (mod x 2) == 0) $ [1..20]
in Python I would have to use either many brackets or useless variables ... is there anything like . and $ in Python?
(I'm not familiar with Haskell, but if I understand your code snippet correctly...)
You can use a list comprehension to perform the filtering and exponentiation.
[i**2 for i in range(1,21) if i%2 == 0]
I would just use whatever idiomatic Python tools are available, such as list comprehensions, as others have pointed out, instead of trying to pretend you're writing Haskell, but if you really must, you could use compose combinator function even in Python:
# this is essentially just foldr (or right `reduce`) specialised on `compose2`
def compose(*args):
ret = identity
for f in reversed(args):
ret = compose2(f, ret)
return ret
def identity(x): return x
def compose2(f, g): return lambda x: f(g(x))
which you could use like this:
from functools import partial
# equiv. of: map (\x -> x^2) . filter (\x -> (mod x 2) == 0) $ [1..20]
compose(partial(map, lambda x: x**2), partial(filter, lambda x: x % 2 == 0))(range(1, 21))
which admittedly does work:
>>> compose(partial(map, lambda x: x**2), partial(filter, lambda x: x % 2 == 0))(range(1, 21))
[4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
...but as you can see, Python lacks certain concepts such as currying and arbitrarily definable infix operators, so even though semantically, the above snippet of code is equivalent (even identical) to the Haskell snippet, it reads quite hellish.
As to the $ operator: it has little relevance in Python — its primary purpose in Haskell is related to operator precedence, which is a non-issue in Python because you can't really use operators most of the time anyway, and all of the built-in operators have predefined precedence.
And whereas $ can additionally be used as a higher order function in Haskell:
zipWith ($) [(3*), (4+), (5-)] [1,2,3]
...replicating this in Python with its (deprecated) apply "combinator" will, again, lead to code that is just ugly:
>>> list(starmap(apply, zip([lambda x: 3 * x, lambda x: 4 + x, lambda x: 5 - x], map(lambda x: [x], [1, 2, 3]))))
[3, 6, 2]
— again, several fundamental limitations of Python are at play here:
laziness isn't built-in and thus not handled automatically, so without "forcing" the starmap using list(), you don't get a "normal" list back;
apply is not (a -> b) -> a -> b but (a1 -> a2 -> ... -> aN -> b) -> (a1, a2, ..., aN) -> b, so you need to wrap the list elements with [] and use starmap not the normal map; this is also a result of the lack of currying;
lambda syntax is verbose because Guido's personal preference is against lambdas, map, reduce, and so on;
Ironically (since list comprehensions are something that Python borrowed from languages like Haskell), I'd probably write the code similarly in both languages:
# Python
for xsquared in [x**2 for x in range(1, 21) if x % 2 == 0]:
print(xsquared)
# legal, but not idiomatic; you don't construct a list just
# to throw it away.
# map(print, [x**2 for x in range(1, 21) if x % 2 == 0])
and
-- Haskell
main = (mapM_ print) [ x^2 | x <- [1..20], x `mod` 2 == 0 ]
or more briefly in each:
# Python
for xsquared in [x**2 for x in range(2, 21, 2)]:
print(xsquared)
-- Haskell
main = (mapM_ print) [x^2 | x <- [2,4..20]]
Functions in Python are more difficult to compose than in Haskell. A Haskell function takes one argument and returns one value. It's easy for the compiler to check that f . g makes sense given the defined type signatures for f and g. Python, however, has no such type signatures (even in 3.5, the type hinting is optional and only used during static analysis, not during runtime).
Further, Python functions can take an arbitrary number of arguments (no currying), and tuples are variable length, not fixed length. Suppose g returns a tuple. Should f ∘ g (my personal choice for a composition operator should such a thing ever be adopted, and Unicode operators be permitted) be equivalent to f(g(...)) or f(*g(...))? Both make sense, and point to the "need" for two different types of composition. What if g's return value has too many or too few values for f? What about keyword arguments to f? Should they be taken from a dictionary returned by g? What seems like a simple operation becomes quite complex to define in Python.
One other thing I may be completely wrong about. I get the impression that whereas each function in Python is compiled as a distinct piece of code, Haskell can compile optimized code for each composition, so that f . g isn't just naively converted to \x -> f (g x). At least in Python, for
def f(x):
return x + 5
def g(x):
return 3 * x
this is what the compiler could generate for f∘g
def fg(x):
return f(g(x))
which would be far less efficient than the equivalent of what I understand the Haskell compiler could generate:
def fg(x):
return 3*x + 5
For this case you should better use a list comprehension like #CoryKramer said.
To apply partial application in Python you should use functools.partial, would be something like this
from functools import partial
def compose(func1, *func2):
return func1 if not func2 else lambda x: func1(compose(*func2)(x))
myMap = partial(map, lambda x: x**2)
myFilter = partial(filter, lambda x: x%2 == 0)
myFunction = compose(myMap, myFilter)
myFunction(range(20))
Since map function returns list which is iterable and filter also you can nest them -
map(function1, (filter(function2,list)))
For more information I would recommend you read the map function documentation also filter function documentation

Pythonic way to do `if x in y where x.attr == val`?

I have a class that represents a polynomial as a collection of terms where each term has a coefficient and an exponent. I am working on the __add__ method of the class and I am wondering what the most effective way to do something like:
def __add__(self, other):
new_terms = []
for term in self.terms:
if there is a term in other with an exponent == term.exponent
new_terms.append(Term(term.coef + other_term.coef, term.exponent))
It strikes me that I'm looking for something such as:
if x in y where x.attr == val
Or in my specific case:
if x in other where x.exponent == term.exponent
Does such a thing exist?
You need to filter your list before doing your contains check. As tobias_k suggested, you can either build a new list, e.g.
[x for x in other if x.exponent == term.exponent]
This works directly in an if statement, because an empty list is False:
if [x for x in other if x.exponent == term.exponent]:
But this does some wasteful work, since it a) has to construct a new list and b) doesn't short-circuit once a result is found. Better is to use the same syntax in a generator expression:
(True for x in other if x.exponent == term.exponent)
Which you can then similarly use in an if statement, but no wasteful work is done:
if next((True for x in other if x.exponent == term.exponent), False):
I think you want [x for x in y if x.attr == val], or use next with the same expression for just the first such value.
In your case, it could look something like this:
def __add__(self, other):
for term in self.terms:
for other_term in (x for x in other.terms
if x.exponent == term.exponent):
term.coefficient += other_term.coefficient
However, this will not work too well. First, __add__ should not modify neither self nor other but instead create a new polynomial. Also, this will ignore any values from other that have a different exponent that any of the terms in self. And third, the performance is pretty lousy, as it loops the list of terms in other for each term in self, giving it quadratic complexity.
Instead, I suggest using a dictionary, mapping exponents in the term to their coefficient. In fact, you could probably just use a collections.Counter for that; it already implements __add__ in the right way. Something like this:
class Poly:
def __init__(self, counts):
self.terms = collections.Counter(counts)
def __add__(self, other):
return Poly(self.terms + other.terms)
def __str__(self):
return " + ".join("%dx^%d" % (c, x) for x, c in self.terms.items())
Example:
>>> Poly({2: 1, 1: 3, 0: 5}) + Poly({3: 1, 1: 2, 0: 3})
8x^0 + 5x^1 + 1x^2 + 1x^3

How to change the look of Python operators?

In order to make Python look more familiar, I've tried to assign an operator symbol to a variable's name,just for educational purposes: import operator equals = operator.eq
This seems to work fine for equals(a,b) but not for a equals b
Is there a way to express that a equals b instead of a == b
No, Python (and most mainstream languages) does not allow this kind of customization. In Python the restriction is quite intentional — an expression such as a equals b would look ungrammatical to any reader familiar with Python.
Not necessarily, but another SO answer shows how you can use this simple trick to "create" new operators. However, they only work if you surround the operator by | | or by << >>:
equals = Infix(lambda x, y: x == y):
print 2 |equals| 2 # True
The best you can do is
def equals(a,b):
return a == b
equals(1,5)
>> False
or
class my:
value = 0
def equals(self, b):
return self.value == b
a = my()
a.equals(3)
>>False
But you should use the built-in operator for readability. This way, a reader can distinguish, at once, an operator, a function, a symbol (a variable), a member function, etc...

How to use infix operators as higher order functions?

Is there any way to use infix operators (like +,-,*,/) as higher order functions in python without creating "wrapper" functions?
def apply(f,a,b):
return f(a,b)
def plus(a,b):
return a + b
# This will work fine
apply(plus,1,1)
# Is there any way to get this working?
apply(+,1,1)
You can use the operator module, which has the "wrapper" functions written for you already.
import operator
def apply(f,a,b):
return f(a,b)
print apply(operator.add,1,1)
Result:
2
You can also define the wrapper using lambda functions, which saves you the trouble of a standalone def:
print apply(lamba a,b: a+b, 1, 1)
Use operator module and a dictionary:
>>> from operator import add, mul, sub, div, mod
>>> dic = {'+':add, '*':mul, '/':div, '%': mod, '-':sub}
>>> def apply(op, x, y):
return dic[op](x,y)
...
>>> apply('+',1,5)
6
>>> apply('-',1,5)
-4
>>> apply('%',1,5)
1
>>> apply('*',1,5)
5
Note that you can't use +, -, etc directly as they are not valid identifiers in python.
You can use the operator module this way:
import operator
def apply(op, a, b):
return op(a, b)
print(apply(operator.add, 1, 2))
print(apply(operator.lt, 1, 2))
Output:
3
True
The other solution is to use a lambda function, but "there should be one -- and preferably only one -- obvious way to do it", so I prefer to use the operator module
you can use anonymous function : apply(lambda x,y : x + y, 1,1)
# Is there any way to get this working?
apply(+,1,1)
No. As others have already mentioned, there are function forms of all of the operators in the operator module. But, you can't use the operators themselves as that is a SyntaxError and there is no way to dynamically change python's core syntax. You can get close though using dictionaries and passing strings:
_mapping = {'+':operator.add}
def apply(op,*args):
return _mapping[op](*args)
apply('+',1,1)
It is possible to give the operators +, -, *, and / special behavior for a class using magic methods, you can read about this here: http://www.rafekettler.com/magicmethods.html
This isn't exactly what you were asking for because this still requires the creation of a method for each operator, but it does allow you to use the operators by symbol in your code. Note that I don't think this is better than the other methods, it is just an illustration of how you can define behavior for operators:
class Prefix(object):
def __add__(self, other):
""" Prefix() + (a, b) == a + b """
return other[0] + other[1]
def __sub__(self, other):
""" Prefix() - (a, b) == a - b """
return other[0] - other[1]
def __mul__(self, other):
""" Prefix() * (a, b) == a * b """
return other[0] * other[1]
def __div__(self, other):
""" Prefix() / (a, b) == a / b """
return other[0] / other[1]
And examples:
>>> prefix = Prefix()
>>> prefix + (12, 3)
15
>>> prefix - (12, 3)
9
>>> prefix * (12, 3)
36
>>> prefix / (12, 3)
4
Of course this method can't be used for a more complex prefix equation like * / 6 2 5 because there is no way to define behavior for adjacent operators, which will always give a SyntaxError (except for a few special cases where + or - are interpreted as making the next element positive or negative).

Categories

Resources