3 ms·
Yeah, they never emailed me the scores either, and told me there was no way to know at the booth... I even joked with them that they were just trying to link it
by squeaky-clean 9y ago
Yeah, they never emailed me the scores either, and told me there was no way to know at the booth... I even joked with them that they were just trying to link it to my fb profile.
I actually didn't catch the trick until I asked someone later if they had gotten the same problem twice, "Almost, but the values were different" which is when I realized it (I blame the beer during opening night). However, as I found out today, because the way they worded the question it was all on a single line (if I remember correctly). So both cases should actually have been True, and I was right both times :P
> (e.g. does pypy do the same? ironpython?)
I wasted... ahem, spent a few hours today playing with this and found a few things, it's pretty neat!
In PyPy, `is` will always be True for primitives. This also means NaN is NaN (but still never == NaN). It doesn't use memory location for things like id() like CPython does, but it guarantees you get a unique representation. [0]
In CPython (3.5.2), it will always cache [-5, 256]. Here's the code that creates that array at startup [1] and each possible init/copy function calls this first to see if it's a cached int [2].
But it can sometimes cache other values! It also depends on if you do it from a module or the repl, and it's different depending on what scope or line each name/value is on. This one weirded out some coworkers, all from one continuous repl session:
>>> x = 500
>>> x is 500
False
>>> x = 500; x is 500
True
>>> def wat():
... x = 500
... return x is 500
>>> wat()
True
>>> x = 500
>>> def wat_wat():
... return x is 500
>>> wat_wat()
False
If you run it from a script you instead get True, True, True, False. You can disassemble it to get a hint at why. One uses STORE_FAST and LOAD_FAST, and the other LOAD_GLOBAL.
>>> disassemble(wat.__code__)
2 0 LOAD_CONST 1 (500)
3 STORE_FAST 0 (x)
3 6 LOAD_FAST 0 (x)
9 LOAD_CONST 1 (500)
12 COMPARE_OP 8 (is)
15 RETURN_VALUE
>>> disassemble(wat_wat.__code__)
2 0 LOAD_GLOBAL 0 (x)
3 LOAD_CONST 1 (500)
6 COMPARE_OP 8 (is)
9 RETURN_VALUE
Now I'm still trying to figure out why STORE_FAST and LOAD_FAST cause it to use the same object, and why those only get called when it's interpreted together. When I figure this out I might put together a longer post about all this.
Also don't use `is` for comparing integers. ;)
[0] http://doc.pypy.org/en/latest/cpython_differences.html#object-identity-of-primitive-values-is-and-id http://doc.pypy.org/en/latest/cpython_differences.html#objec...
[1] https://github.com/python/cpython/blob/master/Objects/longobject.c#L5491 https://github.com/python/cpython/blob/master/Objects/longob...
[2] https://github.com/python/cpython/blob/ba85d69a3e3610bdd05f0dd372cf4ebca178c7fb/Objects/longobject.c#L63 https://github.com/python/cpython/blob/ba85d69a3e3610bdd05f0...
- makmanalp 9y agoWow, this is amazing research! I had no idea the rules actually varied this much. The same like one is especially odd. The LOAD_FAST seems to make sense because it's defined as : "Pushes a reference to the local co_varnames[var_num] onto the stack." (emphasis mine). Also see the global case: In [2]: x = 500 In [7]: def wat_wat_wat(): ...: global x ...: x = 600 ...: return x is 600 ...: In [8]: dis.disassemble(wat_wat_wat.__code__) 3 0 LOAD_CONST 1 (600) 2 STORE_GLOBAL 0 (x) 4 4 LOAD_GLOBAL 0 (x) 6 LOAD_CONST 1 (600) 8 COMPARE_OP 8 (is) 10 RETURN_VALUE In [9]: wat_wat_wat() Out[9]: True But this only goes further to prove my point - it's a bit of a silly question to quiz someone on :-) For one the question didn't seem to be well defined enough, but also it tests something that no one in their right mind would do, and also I don't know if the authors realized these nuances themselves either. I guess it makes for good trivia.
- squeaky-clean 9y agoHaha thanks, I was inspired by David Wolever's talk this year. This is the first time I've gone through the disassembler module or the CPython source, it's much less intimidating than I thought it would be. Also wat! The bytecode for the global case makes sense, but I wasn't expecting True?!
- makmanalp 9y agoYeah, now I'm even more confused!