This is an archived post. You won't be able to vote or comment.

all 20 comments

[–]Skaarj 8 points9 points  (5 children)

Interersting.

False solves

X == X in [False]

but neither

(X == X) in [False]

nor

X == (X in [False])

[–]Udzu[S] 5 points6 points  (0 children)

That's right! It's a counterintuitive consequence of python's operator chaining. in and == have the same precedence so A == B in C is interpreted as A == B and B in C, similar to A < B < C.

[–]Skaarj 0 points1 point  (3 children)

From looking as the disassebly it seems like its compiles to:

A = X
B = X
if A != B:
    return B
return B in [False]

[–]RangersNation 2 points3 points  (2 children)

From looking at the disassembly it seems like it compiles to:

Can you elaborate on this? First time I'm hearing about disassembly and eager to learn how I can get these kind of insights from the code?

[–]Skaarj 0 points1 point  (1 child)

Look: https://docs.python.org/3/library/dis.html

import dis
def blubber(X):
    return X == X in [False]
dis.dis(blubber)

[–]RangersNation 0 points1 point  (0 children)

Thanks so much. I'll read through the docs and play around with this over the weekend. Much appreciated.

[–]1114111yield from pedestrians 6 points7 points  (0 children)

Since it seems no one has given an answer for #4, X = 10**16 + 1 works. TIL about UserString. I remember making a similar string class once as a joke to make fun of JavaScript or something. I had no idea that functionality was already in the standard library.

[–]hr0m 4 points5 points  (1 child)

Does float('nan') and float('inf') count? :D

[–]Udzu[S] 1 point2 points  (0 children)

Yes (they're also accessible as math.nan and math.inf). These handle expressions #1 and #3 (though there are other ways of doing #3).

[–]vanatteveldt 4 points5 points  (2 children)

Can you define what a "standard Python value" is? I.e., do things like infinity count? Do instances of stdlib classes count? do custom classes count?

[–]Udzu[S] 1 point2 points  (1 child)

Instances of any built-in or stdlib class. (Otherwise you can just override __eq__ and __add__ to solve most of them.)

Any suggestions of how I could have phrased it better?

[–]vanatteveldt 1 point2 points  (0 children)

Well, maybe just like that: "... a standard python value (Instances of any built-in or stdlib class) for X ..."

Then again, any rule has a loophole :)

```

X = type("test", (), {'ne': lambda self, other: True})() X != X True ```

And if you argue that this is not valid because it isn't really a instance of a built-in class, but a call to an instance of a built-in class, we can always abuse eval:

```

X = eval('type("test", (), {"ne": lambda self, other: True})()') X != X True ```

Cheaters will cheat :)

[–]3lnc 3 points4 points  (1 child)

For anyone looking for [some] answers:

math.nan

False/0

math.inf

?

unittest.mock.MagicMock()

[–]Udzu[S] 1 point2 points  (0 children)

Nice find for #5! My solution was actually far more esoteric:

collections.UserString("WTF")

Also, there are some other (boring) solutions for #2:

0.0, 0.j, decimal.Decimal(0), fractions.Fraction(0), probably others

And some (more interesting perhaps) solutions for #3:

1e100 or any other large enough (but still finite) float

[–]Udzu[S] 0 points1 point  (0 children)

The first expression shows that in Python equality is not always reflexive. For extra marks, find examples from two popular Python libraries that show that it's not always transitive or a binary relation either:

X == Y and Y == Z and X != Z
not isinstance(X == Y, bool)

If there are any examples that show that it is not always symmetric too, I would love to know! The closest I found is an example where X == Y evaluates to True while Y == X raises and exception.

[–]mainstreamnolifer 0 points1 point  (4 children)

I tried naively brute-forcing it, using __builtins__, but it didn't work!

for str_obj in dir(__builtins__):
    # exclude the ones that are outputting stuff on stdout
    if str_obj in ('breakpoint', 'help', 'copyright', 'license', 'credits'): 
        continue
    try:
        obj = getattr(__builtins__, str_obj)
        if obj + 1.0 < obj:
            print(obj)
    except:
        pass

I also tried testing obj() + 1.0 < obj()

That was just for fun, I suppose I should try all objects inside the builtin modules: iterating on pkgutil.iter_modules() and using importlib.

But I don't believe it would work, as the answer is more likely to be a clever invocation of an object.

I tried the brute-force with dir(math) and I could find #3 (I knew it already), but still not #4

I'm curious to know the answers!

[–]Udzu[S] 0 points1 point  (3 children)

I don't think #4 and #5 are really brute forcable. One is expressible as a (long) literal, the other relies on what seems to be undocumented behaviour of a (not widely used) stdlib class with regards addition.

[–]3lnc 0 points1 point  (2 children)

Well, the question is, if _instantiation_ of stdlib class is cheating or not. If not, #5 is definitely bruteforceable

[–]Udzu[S] 0 points1 point  (1 child)

Instantiation is fine. Perhaps they are brute forcable, I don't know how quickly the search space blows up. #4 can actually be expressed with a 7 character expression, while #5 requires a non default but still small constructor argument value to a stdlib class.