28

I would like to write a statement in python with logical implication. Something like:

if x => y:
  do_sth()

Of course, I know I could use:

if (x and y) or not x:
  do_sth()

But is there a logical operator for this in python?

10 Answers 10

46

p => q is the same as not(p) or q, so you could try that!

Sign up to request clarification or add additional context in comments.

5 Comments

And that is simplier than (x and y) or not x. Thanks
The TTL agrees - but it's not necessarily so easy to see in code, although simpler than the original. A function - i.e. implies(x, y) - might help with transferring the idea more, if such a construct occurs often enough to warrant a name.
@user2246674 Agreed, I would recommend making this a function for clarity.
en.wikipedia.org/wiki/Material_nonimplication also equivalent to p and not(q)
One potential gotcha if you make an implies(x, y) function: because of Python's strict evaluation, the consequent y will always be evaluated (the operation will not be short-circuiting). You would think this would be obvious, but I just spent 30 minutes scratching my head over this problem.
20

Just because it's funny: x => y could be bool(x) <= bool(y) in python.

1 Comment

And this is (finally) conclusive proof that True should be -1 and False should be 0 for booleans! (Instead of the current Python convention of True == 1.) Because then we'd have x => y matching y <= x (which looks like a right-to-left implication) for booleans.
11

There is a converse implication operator:

if y ** x:
  do_sth()

This reads: If y is implied by x.

Credits to https://github.com/cosmologicon/pywat

7 Comments

Yes. This is exactly what I was looking for. And it looks like this converse implication is undocumented, so @Latty 's answer basically is incorrect.
@running.t This is something that happens to have the same effect as x => y, but is not an operator for that purpose. This is the power operator, and is not a logical operator, but a numerical one. It does not return True or False, but a number. This is slower, and could potentially introduce bugs, not to mention being incredibly unclear and hard to read. I would highly recommend against ever doing this, and instead would use not(p) or q as per Juampi's answer.
I would have liked to have a bitwise version of this too.
@GarethLatty, a "purpose" of an operator only makes sense for a particular class/type (operators can and should be overloaded). Note by the way that the + operator is arguably not for the purpose of doing "Hell" + "o". Regarding the power operator ** for Booleans that is not properly overloaded and does not return True/False, IMO this is a Python's bug or misfeature. If A and B are two sets, then A^B (A to the power B) is the standard notation for the set of functions B -> A. Under Curry–Howard correspondence, a function B -> A represents a proof of B => A.
@Alexey "Operators can and should be overloaded." is a strong statement. Operators are hard to search for and rely on the user's perception of the operator, so should generally be avoided in favour of functions where the meaning isn't very clear to most people. The vast majority of people reading that code will find it less clear than the alternative, and—regardless of it being a bug or intentionally not done—it isn't implemented efficiently. You can argue that shouldn't be the case, but it definitely is at the moment. Given that, I'd highly recommend against it.
|
6

Your question asks if there is a single logical operator for this in Python, the simple answer is no: The docs list boolean operations, and Python simply doesn't have anything like that.

Obviously, as Juampi's answer points out, there are logically equivalent operations that are a little shorter, but no single operators as you asked.

2 Comments

Please take a look at this answer. It looks like not everything can be found in docs.
@running.t It is not in the docs because that answer is wrong - there is no such operator, instead, it is an abuse of another operator that happens to produce the same result. The end result of using that would be horribly unlcear, inefficient code which may introduce bugs.
3

Additional details based on what I have found here and there as I was looking for an implication operator : you can use a clever hack to define your own operators. Here is a running example annotated with sources leading me to this result.

#!/usr/bin/python

# From http://code.activestate.com/recipes/384122/ (via http://stackoverflow.com/questions/932328/python-defining-my-own-operators)
class Infix:
    def __init__(self, function):
        self.function = function
    def __ror__(self, other):
        return Infix(lambda x, self=self, other=other: self.function(other, x))
    def __rlshift__(self, other):
        return Infix(lambda x, self=self, other=other: self.function(other, x))
    def __or__(self, other):
        return self.function(other)
    def __rshift__(self, other):
        return self.function(other)
    def __call__(self, value1, value2):
        return self.function(value1, value2)

from itertools import product

booleans = [False,True]

# http://stackoverflow.com/questions/16405892/is-there-an-implication-logical-operator-in-python
# http://jacob.jkrall.net/lost-operator/
operators=[
    (Infix(lambda p,q: False),                  "F"),
    (Infix(lambda p,q: True),                   "T"),
    (Infix(lambda p,q: p and q),                "&"),
    (Infix(lambda p,q: p or q)           ,      "V"),
    (Infix(lambda p,q: p != q)           ,      "^"),
    (Infix(lambda p,q: ((not p) or not q)),     "nad"),
    (Infix(lambda p,q: ((not p) and not q)),    "nor"),
    (Infix(lambda p,q: ((not p) or q)),         "=>"),
    ]

for op,sym in operators:
    print "\nTruth tables for %s" % sym

    print "\np\tq\tp %s q\tq %s p" % (sym,sym)
    for p,q in product(booleans,repeat=2):
        print "%d\t%d\t%d\t%d" % (p,q,p |op| q,q |op| p)

    print "\np\tq\tr\tp %s q\tq %s r\t(p %s q) %s r\tp %s (q %s r)\tp %s q %s r" % (sym,sym,sym,sym,sym,sym,sym,sym)
    for p,q,r in product(booleans,repeat=3):
        print "%d\t%d\t%d\t%d\t%d\t%d\t\t%d\t\t%d" % (p,q,r,p |op| q,q |op| r, (p |op| q) |op| r, p |op| (q |op| r), p |op| q |op| r)
        assert( (p |op| q) |op| r == p |op| q |op| r)

Comments

3

I would argue a more readable one-liner would be

x_implies_y = y if x else True

In your original example:

if (y if x else True): do_sth()

Comments

1

You can use the comparison operator <= to get an implication for two variables. Examples:

A   B   A <- B  A <= B
0   0   1       1
0   1   1       1
1   0   0       0
1   1   1       1

1 Comment

This is wrong. Writing A <- B means B implies A, which is false when A is false end B is true, but A <= B is true in that case. A <= B can be interpreted, counterintuitively, as A implies B.
0

I found XOR to be a good solution. you can change A implies B to not A or B. Then you use xor to negate A like this

A^1 or B

Since A xor(^) 1 is equal to not A

1 Comment

It is more common in Python to use not A instead of A ^ 1 to negate a boolean, though.
0

You can use == (which is an ARITHMETICAL operator) instead of logic equivalency as well as use <= (which is an ARITHMETICAL operator) instead of logic implication. But you get onto a minefield in this case, because:

  1. you should be sure that your arguments are pure int 0 or 1 only,
  2. precedence of arithmetical <= and == is HIGHER than precedence of logical not (but it should be even lower than precedence of or in a world of logic),
  3. an "arrow" you see as <= looks opposite to an actual direction of implication (which can be confusing).

Be careful.

Comments

0

Although it looks terrible, you can represent "A implies B" in Python by "A <= B".

from itertools import product

print("A        B        A => B")
for t in product([True, False], [True, False]):
    print(f"{str(t[0]):5}    {str(t[1]):5}    {str(t[0] <= t[1]):5}")

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.