0

I will keep this short. I was reviewing code for Hex Filter (To filter out non-character ASCII values)

code:

HEX_FILTER = ''.join([(len(repr(chr(i))) == 3) and chr(i) or '.' for i in range(256)])

Output:

................................ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~..................................¡¢£¤¥¦§¨©ª«¬.®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ

I was confused on what's going on, so I wrote my approach to get above output. My code is as follows:

HEX_FILTER = ''.join(['.' if (len(repr(chr(i))) != 3) else chr(i) for i in range(256)])

The idea is repr of non-alphabet will be more than 3. If it's not 3 use '.' else use the character.

I cannot wrap my mind around on as to, How len(repr(chr(i))) == 3) and chr(i) or '.' equates to '.' if (len(repr(chr(i))) != 3) else chr(i)

4
  • One easy-ish way to see if there is a difference is to write a script to loop thru all the T/F values for the 3 pieces of the 2 code versions and print out a truth table for each. There's only 2^3 = 8 combinations. But maybe you already know there isn't a difference, since that is your question... Commented Mar 13, 2021 at 7:58
  • Yes, I know both codes yield the same result. I was a little surprised to notice and and or is used instead of if and else. That got me wondering, which one of them is efficient in terms of time complexity. And is there a way to use and and or in complex if-else branching, Even more on what's happening behind the scene Commented Mar 13, 2021 at 8:03
  • 2
    @xdhmoore the and and or operators work for any object that supports being evaluated in a boolean context, so there are many more possible combinations to test. Commented Mar 13, 2021 at 9:40
  • @mkrieger1 yeah I think you're right. Especially since the AND/OR operators don't convert to Boolean but pass thru the original value as trincot's answer mentions. Commented Mar 13, 2021 at 21:19

1 Answer 1

2

The original expression makes use of the fact that a boolean operator like and and or always evaluates to one of the operands, not necessarily a boolean. This is somewhat an extension to the mathematical notion of boolean logic where all involved values are booleans.

So:

  • if the left operand of an and operator is:

    • truthy, the operation will evaluate to whatever the second operand is.
    • falsy, the operation will evaluate to whatever the first (falsy) operand is.
  • if the left operand of an or operator is:

    • truthy, the operation will evaluate to whatever the first (truthy) operand is.
    • falsy, the operation will evaluate to whatever the second operand is.

If you apply those rules to the expression, you can see that the first expression is a true boolean. In case it is false, the and operation will also evaluate to false, which then serves as the left operand to the or operator. By consequence, the or operation will evaluate to the rightmost operand, i.e. to '.'.

If on the other hand the first expression is True, then the and operator will evaluate to the second operand, i.e. chr(i). That value happens to be always truthy, as it can never be the empty string, and so the or operation will just evaluate to that and will not even consider the final operand.

So the two constructs are equivalent, but only when the middle operand (in this case chr(i)) is always truthy.

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

2 Comments

Ok, this wonderful explanation clears it, But doesn't this go against Zen Of Python - Readability counts.
Sure, for readability I would also go with if...else, but I'm sure there is a group of coders who feel otherwise. In the end it is a matter of opinion.

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.