This isn't a generalist quiz, nor is it a good baseline for interviewing candidates for the hiring process, this wouldn't tell me anything about the application of their skillset.
This isn't a generalist quiz, nor is it a good baseline for interviewing candidates for the hiring process, this wouldn't tell me anything about the application of their skillset.
It basically relied on this fact...
x = 256
x is 256 # True
y = 257
y is 257 # False
Which for one, you shouldn't use `is` to compare integers in Python. I wish I could have just written that as my answer.Secondly, you need to be aware the CPython uses an integer cache which causes the answers to be different. You'll actually get different answers based on whether you run it as a file, enter it line-by-line into the interpreter, or use a different implementation such as PyPy.
https://stackoverflow.com/questions/15171695/whats-with-the-...
There wasn't any point to the quiz, so it's okay that they put in silly questions like that. But it's clearly there just to try and trick you, and not quiz you on anything relevant. Most of the other questions were tricks of the sort, or or Python 3 specific gotcha's.
I wouldn't expect anyone else to know it, and don't consider it something positive or negative as far as programming skill is concerned. It's kind of related to interest, but admittedly I waste a lot of time playing with stupid details like this in programming languages, so maybe it actually makes me less productive than the average person.
[0] "Write a program that makes 2 + 2 = 5"
https://codegolf.stackexchange.com/a/28851
edit: wording change
Knowing fb, there might well have been; if they had a facial recognition webcam up and noted applicant scores no one would hear about it. They'd probably just call it an "experiment in hiring"
By the way y == 257 does work.
>>> x = [1,2,3]
>>> y = [1,2,3]
>>> x == y
True # two lists with the same values; equal
>>> x is y
False # two different lists; doesn't matter that they contain the same values
>>> z = x
>>> z is x
True # same list object in memory
Because here you want to know if the two integers are logically equal, not if they're necessarily the same object in memory, you want "==" and not "is". Due to an optimisation, "is" might work for small integers, depending on implementation, but the takeaway is not to use "is" for value comparisons; that's what "==" is for.-5 to 256 (inclusive) [https://github.com/python/cpython/blob/master/Objects/longob...]
Given this, the expression "1" on the current version of cpython returns the same object from the small integer cache every time. Not just an equal object, the very same object. Overall, don't depend on it - it's an optimization and can change all the time.
-5 to 256 (inclusive) [https://github.com/python/cpython/blob/master/Objects/longob...]
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#objec...
[1] https://github.com/python/cpython/blob/master/Objects/longob...
[2] https://github.com/python/cpython/blob/ba85d69a3e3610bdd05f0...
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.Also wat! The bytecode for the global case makes sense, but I wasn't expecting True?!
- Reference semantics for pretty much everything, except perhaps basic types such as integers - but those are generally "immutable" (e.g. no 5.add(6) mutating the "original object" in-place) making by-reference vs by-value moot.
- Arguments copy the reference, they do not alias the original reference.
- Mutating functions, if the return value isn't being used, are either being misused (e.g. the code has a bug) or mutate the original object in-place.
- Closures alias the same variables
This could be JavaScript, ActionScript, Ruby, Powershell, Squirrel, PHP, ... hell, even a lot of the compiled statically typed languages share similar semantics. I'd expect someone coming from, say, a pure C/C++ background to have some trouble though, which is perhaps the point you're getting at.
I believe that it tries to be a bait and rubbish filter at the same time.
For a few questions, I also just booted up my Python shell, rather than comprehending the script. :/
It would have been helpful if each question had the relevant language specific information - for example, reference/value semantics.
The problem is that the function makes no frigging sense without the argument being a reference, so you're naturally forced to assume that it is.
that being said. Some remarks about questions:
1st fails for all NaN/empty. Returning negative infinity is hardly a good choice for an array full of NaN.
2nd I didn't like this one: "children" comes from nowhere. There is no 'definition' of order, so 'first' is quite confusing, perhaps 'any' suits better.
5th I'd have expected white spaces in the toString rendering of the array (checked via inspect element). Had to make some assumptions.
7th since only variables i1 and i2 are defined and 3rd/4th answers make no sense as loop predicates, the entire merge function body is rather pointless.
8th About the correct answer:: One problem with ASCII is that it only support English characters (and a few other European languages). The characters are Latin and even Ural based languages like Estonian/Finnish/Hungarian use the same base for alphabet. "Unicode is like ASCII, but larger.", I'd never consider them a"like", for instance converting hexdecimal numbers to their asciis code is 5byte assembly for 8086. Also ascii is sort of a code page while unicode tries to combine all code pages together.
10th But because they share memory with other threads in the same process, threads must synchronize access to shared data to maintain data integrity. "Synchronize access" implies certain data model/locking paradigm. It's possible to have entirely lock free/copy-on-write multithreaded code that will exhibit no need for explicit synchronization. Alternatively some code could still be correct with benign data races (but that usually comes close to poking the dragons)
11th best practice is generally to use prepared statements, which lets the database itself protect against SQL injections. The statement is not necessarily true, the prepared statement could be just standard execution with parameters being escaped by the database driver (client), technically still performing the escaping part.
12th Side channel, timing attack is correct but virtually impossible to observe due to the very short nature of hashes and the fact they are all in the L1 by the time the check is performed -- even SHA512 is just one cache line, processing the comparing function yields 10ns or so time difference. The real concern is "the user_submitted_hash" -- users should not be submitting hashes directly as that precludes salting and invalidates use of any =slow= hashing function as the attacker just submits more hashes. IMO a bad question.
14th One advantage of DFS, however, is that it uses much less memory. BFS must store a queue of nodes to visit, and this queue can grow to (order) the size of the entire graph. The statement is not universality true and the worst case scenario is the same, a good answer https://cs.stackexchange.com/a/299. More importantly DFS can be executed in parallel.
I started reading the green part after first few answers, hopefully the remarks are useful (and not snark).
queue.extend(node)
queue.extend([node])
queue.extend(node.children)
Sure, I could take a guess which one of those appends the contents of "node" to the end of "queue", but I'd be guessing about syntax, not programming.After that, and question 3 about what happens when you assign to a function argument, I realized it was a Python quiz and stopped reading.
# assume "node" is an object with "value" and "children" properties
would make this question clearer.From a python-specific viewpoint, dequeue.extend appends a given list to the end of the queue. The first example will raise an exception, but the other two are perfectly valid, and their behavior isn't special to python - it's just asking whether you'll want to vi it this same node again, or the node's children.
Incidentally, it's not as if there's any standard library 'node' class with a children method. This was a structure they defined, but did not share the definition of.
Ahh, that makes things much clearer. Since they weren't otherwise mentioned, I supposed that "value" and "children" were properties of some existing Python collection object - and that the question was asking how "queue.extend" expected that collection to be passed in.
I guess this is the inverse of a language-specific question - if one knows that "children" has no significance in Python then I suppose the question would be clearer.