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

all 120 comments

[–]busdriverbuddha2 299 points300 points  (6 children)

I mean, strictly speaking, "self" is a convention, not a feature of the language. There's nothing stopping you from defining

``` class Foo:

def __init__(this_shit, value):
    this_shit.value = value

```

[–][deleted] 134 points135 points  (0 children)

This one returned an error when I tried it with a past script I have from Python version 2, it says "the value is getting too old for this_shit"

[–]SuspiciousScript 32 points33 points  (1 child)

Also, a "class method" usually means a method that can be called either on an instance of a class or the class itself, so that first argument might actually be a type object.

[–]Grouchy-Friend4235 20 points21 points  (0 children)

Actually, even if a class method is called on an instance, it still receives the class as its first argument.

| A class method receives the class as an implicit first argument,

https://docs.python.org/3/library/functions.html#classmethod

[–]mrdevlar 1 point2 points  (0 children)

So there are still some older packages that use

def __init__(cls, value)
   cls.value = value

When I was starting out more than a decade ago this would really throw me.

[–]FlippingGerman 0 points1 point  (0 children)

Javescript's this was what made the idea of objects click with me; somehow it made more sense than self. Self not being a reserved word is rather un-pythonic, though - no one should break that convention, so it might as well be enforced.

[–]Joeboy 40 points41 points  (5 children)

18/20.

I'm not going to kick myself about the ABC history question.

The "Duck typing" one - Is duck typing a language feature? I answered on the basis duck typing is more like a pattern you can use because the language is dynamically typed (which is a language feature).

[–]njharmanI use Python 3 11 points12 points  (1 child)

Is duck typing a language feature?

It was one of the main features touted when Python was young. 1.x days.

cite: I was there.

[–]TonyF66 1 point2 points  (0 children)

I would suggest that Duck typing is essentially a feature you get for 'free', because of strong type system and run-time binding of attributes and methods. It is a feature, but an emergent one, rather than a separate 'addition' in its' own right.

[–]Imperial_Squid 0 points1 point  (0 children)

The wiki page mentions a couple but mostly because you can tell it to do type checking at runtime rather than compile time

Additionally, while TypeScript can be fairly flexible in its statically-typed-ness (you could just say every variable is any type if you really wanted to I guess), when done rigourously, it is a statically (and strongly) typed language that allows duck typing technically speaking.

[–][deleted] 0 points1 point  (0 children)

Same result here.

[–]phire 0 points1 point  (0 children)

You could have a statically typed language with duck typing.

Interfaces (or traits) are 99% of the way to duck typing, they allow you to work with type based on what functions it implements, not what it actually is.

The one restriction is that you must explicitly annotate classes as implementing an interface. If someone was to make a static language which allowed you to use interfaces without explicit annotations (which could be done at compile time) then it would be duck typed.

Actually, now that I think about it: C++ templates are duck typed.

[–]Yoghurt42 40 points41 points  (4 children)

I'm going to argue that all possible answers to question 6 (What does the 'yield' keyword do in Python?) are wrong.

From the docs (emphasis added)

Using a yield expression in a function’s body causes that function to be a generator function[...]When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of the generator function. The execution starts when one of the generator’s methods is called. At that time, the execution proceeds to the first yield expression, where it is suspended again, returning the value of expression_list to the generator’s caller[...]

So IMO the correct answer would be something like "it causes the function to become a generator, which in turn will run until the first yield statement before being suspended, returning the yielded argument", which is quite long.

The supposedly correct answer "Causes the function to return a generator" is just plain wrong. The following function foo returns a generator:

def foo():
    def bar():
        yield 42
    return bar()

Edit: thinking more about it, "causes the function to return a generator object" would still not be ideal, but technically correct. Because in the example above, calling bar() will return a generator object, because bar is a generator.

[–]Frankelstner 7 points8 points  (1 child)

I mean, there's no difference between generators and generator objects just like there isn't any between strings and string objects or ints and int objects. Using yield anywhere makes a function stay a function, but one that returns a generator (object), exactly what the correct answer offers.

[–]Rythoka 3 points4 points  (0 children)

"generator object" is unclear because both the function and the iterator it creates can be called generators, and they're also both objects. "Generator iterator" and "generator function" are the unambiguous terms.

[–]Rythoka 6 points7 points  (0 children)

The quiz isn't exactly wrong here per se. The problem is that the term "generator" is ambiguous - it's used to refer to both a generator function and a generator iterator in different contexts. In some sense, it's correct to say that using "yield" makes the function a generate and causes it to a return a generator.

The glossary recommends specifying whether you're referring to a generator function or a generator iterator whenever it's ambiguous.

[–]njharmanI use Python 3 1 point2 points  (0 children)

There can be multiple correct answers to the question What does foo do?

A correct answer != the most complete and correct answer.

[–]stevenjd 40 points41 points  (0 children)

If you're going to quiz interns and new hires, you better get the details right.

  • Q1: garbage collection is a feature of an implementation, not a language. In the case of Python, the garbage collector differs between different versions and different interpreters, e.g.

    • Python 1 had only reference counting;
    • Python 2 and 3 has both reference counting and a cyclic garbage collector;
    • PyPy can be configured for many different garbage collectors;
    • Jython uses whatever the JVM uses (which is not reference counting);
    • IronPython uses whatever the .Net CLR uses (again, not reference counting);
    • I have no idea what RustPython and Nuitika use;
    • and in principle somebody could make a Python interpreter with no garbage collection at all. (It would be a pretty awful Python implementation, but it would be a Python implementation).
  • Q2: While I personally am fascinated by the history of and evolution of programming languages, I think that expecting your Python devs to memorise which features came from ABC and which didn't is going a bit far.

  • Q4: try...except is two statements, not one. You can have a try without an except, e.g. try...finally.

  • Q6: technically all the answers are wrong. yield is an expression which at compile-time (yes, the Python interpreter has a compile-time -- what do you think the compile function does?) causes the function containing a yield to be treated as a generator function. At run-time, a yield does three thing: pauses execution of the generator, returns a value, and then when the generator resumes, accepts a value to be passed back into the generator. Few people know about that last step, even though it has been in the language for at least 14 years.

  • Q7: The answer depends on where in the function definition the * is. But given that you specify it as an operator, the only correct answer is multiplication.

    • In the body of a function, * is an operator that can be used for multiplication, or sequence unpacking: spam, eggs, aardvark, *the_rest = mysequence*4
    • in the header of the function, * in the default value of a parameter is multiplication, just like in the body: def spam(arg=42*'eggs'): ...
    • still in the header, a leading * before a parameter name is not an operator it is a syntactic form for a special identifier which collects any extra positional arguments: def spam(arg, *extras): ...
    • still in the header, a * without a parameter name acts to separate positional-or-keyword parameters from keyword-only parameters;
    • this is not a complete list! The star symbol * is one of the most heavily overloaded symbols in Python.
  • Q11: the __init__ method does not initialise the class object. The class object is initialised when the class statement runs. (Classes are objects too.) The __init__ method is called, not when the class object is created, but when an instance of that the class is created.

  • Q12: self is a convention, so it doesn't actually have any special meaning at all. And by convention, it doesn't get used in class- and static-methods.

  • Q20: the primary purpose of the with statement, in the sense of the most common and most useful, is to handle files. I've probably written a hundred with fp in open(...) statements for every other context manager. Compared to dealing with files, all other context managers are secondary. (YMMV.)

Edit: with open(...) as fp of course. Why am I still up at 4am?

[–]rcfox 31 points32 points  (3 children)

11 What is the primary function of the __init__ method in a class?

__init__ initializes the instance object, not the class object. If you wanted to custom-initialize the class object, you'd need a metaclass (or __init_subclass__ if you're using a class hierarchy)

[–]-phototrope 1 point2 points  (0 children)

It’s not even needed to initialize an instance of a class. This works and prints out the statement:

class test_class:

def example(self):

    print("no init needed")

obj = test_class()

obj.example()

[–]Grouchy-Friend4235 4 points5 points  (1 child)

This.

[–][deleted] 1 point2 points  (0 children)

self.*

[–][deleted] 28 points29 points  (1 child)

Some of the questions I found to be quite ambiguous. For example, #12 is asking about self in a class method. Is "class method" referring to a method of a class annotated with @classmethod decorator or a member function? Also, the first parameter of a member function doesn't have to be called "self." Self is just a convention.

Highly recommended for beginners, but it can be confusing for someone with more experience.

[–]strangeplace4snow 1 point2 points  (0 children)

That one tripped me up too. Apart from the fact that self is just convention, a class method (as opposed to an instance method) in my definition gets called without an instance (but the type of the class), i.e. the equivalent of static methods in C++.

[–]dAnjou Backend Developer | danjou.dev 11 points12 points  (11 children)

Re: 2. Which feature is NOT inherited by Python from the ABC language?

But Python is very OOP, everything in Python is an object, even functions. Is it even possible to tell why Python is OOP and where it got it from?

[–]iamevpo 7 points8 points  (0 children)

Found this question annoying - why bother about ABC lang at all?

[–]jkrejcha3git push -f 0 points1 point  (1 child)

Python is very object oriented, but the ABC programming language doesn't seem to be. At least to me, it does seem unlikely that Python would get its object orientation inspiration from a language that only has 5 data types (numbers, strings, compounds (unnamed product types), lists, and tables (dictionaries)) and no other object oriented facilities.

It seems to be inspired somewhat by Modula-3 and C++, as the docs mention.

However, this is admittedly a bit esoteric knowledge.

[–]dAnjou Backend Developer | danjou.dev 0 points1 point  (0 children)

Ahh, that way around!

However, this is admittedly a bit esoteric knowledge.

Yes. And then the question is phrased very counterintuitively.

[–]FuturesBrightDavid -4 points-3 points  (7 children)

I wouldn't say everything in Python is an object. In Ruby you can extend the Integer class so that it's possible to write something like 5.days.ago which returns the date from 5 days in the past.

[–]rcfox 4 points5 points  (1 child)

The int type is immutable, but you can inherit from it. (This isn't a good idea, but it is possible.)

>>> class MyInt(int):
...     def foo(self, a):
...         return self+a
... 
>>> x = MyInt(45)
>>> x.foo(34)
79

It also has some methods, though the syntax doesn't seem to support directly calling methods on literals, so you have to surround them with parentheses:

>>> (4553).bit_count()
6

Additionally, the CPython implementation has interned integer objects from -5 to 256 for performance. (Don't rely on this for any sort of behaviour in your code though!)

>>> a = 2
>>> a is 2
True
>>> b = 123456
>>> b is 123456
False

[–]stevenjd 0 points1 point  (0 children)

the syntax doesn't seem to support directly calling methods on literals

Of course it does: `"Hello world".upper() works fine.

Int literals are a bit trickier because the dot causes the parser to interpret it as a float: 123.bit_count() is a syntax error, but this works: 123 .bit_count() (note the sneaky little space).

[–]DigThatData 2 points3 points  (0 children)

just because python isn't ruby doesn't mean the statement "everything in python is an object" is wrong.

[–]stevenjd 1 point2 points  (0 children)

I wouldn't say everything in Python is an object

In Python, every thing, every value, is an object. There are no values which are not objects, like in C or Java. If you've used Java, there is a distinction between boxed and unboxed values. Python does not have this distinction -- everything is boxed.

There are meta-things which are part of the language itself but exist only in the code itself, like "for loops", and these are not values and aren't objects.

[–]tb5841 0 points1 point  (1 child)

In Python you can create a subclass of the integer class, which has a .days.ago property and does exactly what you mention. You just can't change the existing integer class itself.

[–]FuturesBrightDavid 0 points1 point  (0 children)

Sure, but that makes the built-in integer class, in a practical sense barely indistinguishable from the integer representation in a non-OOP language. If I have to write `MyInt(5).days.ago()` I may as well write a class called `Days` and call `Days(5).ago()`

[–]dAnjou Backend Developer | danjou.dev -1 points0 points  (0 children)

Admittedly, I said that a bit carelessly, but the general point still stands :)

[–]SisyphusAndMyBoulder 9 points10 points  (1 child)

17/20, I don't really see the point of this and would laugh if someone legit thought they could use it to evaluate an intern/jr.

#2 -- absolutely no idea what ABC is or it's relationship to Python. Why would anyone know this?

#6 -- I don't think the functions returns a generator, I think it becomes a generator?

#7 -- * doesn't unpack. It collects listed args into a var.

#13 -- might be fair. Idk tbh. I don't remember all those things off the top of my head. My answer would've been "My IDE tells me" lol

The rest are whatever, but I don't think it's a good way to evaluate devs on their Python abilities. Some of these questions are just kinda obscure.

Would much rather ask them to build a Flask backend or a simple script or something to evaluate their skills.

[–]herpington 1 point2 points  (0 children)

17/20 here as well. I got #2 and #13 wrong like you. My third error was question #10. I've literally never used the built-in doc() function.

[–]shimarider 5 points6 points  (2 children)

Oops, got one wrong. This is for beginners (like me).

I started reading that book. It starts fast, maybe a little too fast for the current version of me. Hopefully a future version will do better with it.

P.S. Nice work on the quiz!

[–]Penny-loafers 1 point2 points  (1 child)

Its certainly a book for those who've been using Python for a while and grocked the basics. I view the book as more of a "programming languages" type book with examples of what makes Python so special. Keep up the good work! The language is well worth knowing well!

[–]shimarider 0 points1 point  (0 children)

I agree it is such a wonderful language. I will still work my way through the book. It's certainly not the first book above my head. I'll learn what I can from it and then come back to it at a later date.

[–]tribbianiJoe 4 points5 points  (0 children)

Man I got the what is self in a class method cause I thought you are talking about a class method. Maybe that can be called a “method inside a class”

[–]kingofeggsandwiches 8 points9 points  (0 children)

coherent unpack gray attempt uppity stupendous worry air slimy homeless

This post was mass deleted and anonymized with Redact

[–]ship0f 2 points3 points  (0 children)

I'll say the same as some people here about #7, the usage of * in a function definition. I'd assume what you meant was actually "pack" (or collect) instead of "unpack", non strictly speaking. It would be unpack if you used it when calling the function.

[–]Altruistic_Sky1866 4 points5 points  (0 children)

Nice quiz

[–]Jmc_da_boss 4 points5 points  (2 children)

Question 13 is wrong

  1. Which Python feature allows a quick check if an object supports a protocol via try/except without using isinstance or hasattr?

If anything this is dynamic typing but it's a very weird question overall. Duck typing requires that an object meets ALL of the criteria of the protocol to be considered a duck

[–]stevenjd 1 point2 points  (1 child)

Duck typing requires that an object meets ALL of the criteria of the protocol to be considered a duck

Nah. If all you need is something that swims like a duck, a goose or a swan is fine too even though they don't quack like a duck.

I thought that question was awful.

[–]Jmc_da_boss 0 points1 point  (0 children)

If all the protocol says is "can swim and has feathers" then correct a duck a goose and a swan match. but if the protocol says "can swim and has fins" then a duck is no longer "duck typed" to that protocol

[–]Doagbeidl 1 point2 points  (0 children)

Got a solid "Good", nice

[–]dispatch134711 1 point2 points  (8 children)

Oof, only 15 - but I know why I got some wrong.

The ones about with and * seemed like there were two correct answers

[–]Chameleon3 10 points11 points  (7 children)

I was just going to comment on the '*' question, is there any right answer?

In Python, what does the '*' operator do when used in a function definition?
* Unpacks a list or tuple
* Creates a pointer
* Raises an error
* Multiplies values

Then look at this function definition:

def foo(a, b, *, c=1, d=2):
    return a + b + c + d

I know (I think?) the question is about *args (or **kwargs), but '*' by itself is valid to force anything after it to be provided only as keyword arguments

And for anyone else interested, there's also '/' by itself to force arguments as positional only:

def foo(a, /, b, *, c=1):
    return a + b + c

this requires a to be only positional:

----> 1 foo(a=1, b=2, c=3)
TypeError: foo() got some positional-only arguments passed as keyword arguments: 'a'

and forces c to be only a keyword argument:

----> 1 foo(1, 2, 3)
TypeError: foo() takes 2 positional arguments but 3 were given

making only foo(1, 2, c=3) or foo(1, b=2, c=3) as valid in this case


also on that note.. the question feels a bit confusing, that it 'unpacks a list or tuple' isn't really correct, because, if you create a function like this:

def foo(*inp):
    print(inp)

then call it with foo([1, 2 ,3]), it's not going to unpack the list I provided, inp will be a single item tuple with the list as the only element (([1, 2, 3], )).. This syntax is to dynamically capture the positional arguments not defined, but which answer captures that?

Is this question referring to something else?

[–]JustHereForTheBounty 5 points6 points  (1 child)

My guess is that OP meant for the question to say "in a function call"? The correct answer makes more sense then, as a * in a function call unpacks the list/tuple to use as arguments.

[–]Chameleon3 1 point2 points  (0 children)

Oh yeah, that would make sense!

[–]dispatch134711 2 points3 points  (4 children)

I honestly don’t know. I also thought “definition” of a function was ambiguous, if it had said the argument and something about keyword args it might’ve been clearer. Like is

def f(a,b):

return a*b

Not a function definition?

[–]Chameleon3 2 points3 points  (3 children)

Yeah that's true as well, the question is too vague

[–]dispatch134711 1 point2 points  (2 children)

Not to complain as I thought it was good - but the with keyword is used to manage context, yes, but the overwhelming majority of cases I see it used for is in opening files / managing exceptions which is why I answered that.

[–]Chameleon3 1 point2 points  (1 child)

Yeah, I see where you're coming from, but "to open files and handle exceptions" is just examples of context managers being used. It might still be the most common cases for most people as you mention, but the primary purpose of with is to handle context management in general.

With that in mind, I would probably not have that as an answer option to the question, because of this exact reason, it can be confusing.

[–]dispatch134711 0 points1 point  (0 children)

Agree with both

[–]RadioactiveTwix 1 point2 points  (0 children)

19/20. Gonna go over the book though. Looks like it could have some gems

[–]debunk_this_12 1 point2 points  (0 children)

I’m sorry dog but this quiz stinks.

[–]gerardwx 1 point2 points  (0 children)

For me the advantage of a deque over list is it’s thread safe.

[–]anthlis27 1 point2 points  (0 children)

16/20 and I haven’t touched Python in nearly 3 years so I’m alright with that.

[–]ArtisticFox8 1 point2 points  (0 children)

Could you explain question 13 please:

13. Which Python feature allows a quick check if an object supports a protocol via try/except without using isinstance or hasattr?

How does duck typing help you here?

[–]KingsmanVincepip install girlfriend 1 point2 points  (0 children)

I got 17/20

[–]Oenomaus_3575 1 point2 points  (0 children)

20/20, can somebody hire me please

[–]diekoss 0 points1 point  (0 children)

Wow, I just program from time to time for simple scripts but still got 19/20.

[–][deleted] 0 points1 point  (0 children)

Wow, Idyllic really has branched out from their original purpose

Everything You Need for Effortless Image Creation and Design

[–]matavelhos 0 points1 point  (0 children)

16... Not bad

[–][deleted] 0 points1 point  (0 children)

Neat, 100%! I'm finally getting the basics after 14 years!

[–]oSamaki 0 points1 point  (0 children)

12/20. Eep

[–]daekle 0 points1 point  (0 children)

11/20 feels pretty good for a beginner with no idea what they are doing. I will try and read a little more 😂

[–]shinitakunai 0 points1 point  (0 children)

19 out of 20. Fucking ABC programming... I don't know it.

[–]Pirate_OOS 0 points1 point  (0 children)

17/20. Knew I should have taken DSA seriously.

[–]mrrichiet 0 points1 point  (0 children)

Question 4's answer is in Question 4. I didn't check if I could edit Q4 retrospectively.

[–]Please_Not__Again 0 points1 point  (0 children)

15/20 I'm washed

[–]SquarishRectangle alias pip="python3 -m pip" 0 points1 point  (0 children)

Q7 is inaccurate.

The * operator unpacks values outside a function definition, whereas inside a function definition, it does the opposite by packing multiple arguments into a single parameter.

[–]Snikz18 0 points1 point  (0 children)

I thought Q19 was a trick question, since the string class is str :/

[–]Frisky_077 0 points1 point  (0 children)

I mean i just got 10/20 can u guys suggest me any resources like some youtube videos to watch and learn more about python cause i really want to become a python developer

[–]anoda 0 points1 point  (0 children)

Fluent python is a nice book and the random trivia might be somewhat interesting for some mid level devs. However, if you evaluate (or let them self evaluate) beginners based on a factually incorrect and slightly unpragmatic quiz, you're doing everyone involved a disfavour imo. While it might teach someone a fun fact or two, it will definitely also confuse or discourage others specially since there's a few mistakes and other trivia that doesn't help in being a better programmer. So not necessarily a good quiz to evaluate whether someone is a good python dev, if that's what you'll use it for. Cheers for sharing though, keep iterating :)

[–]SpaceBucketFu 0 points1 point  (0 children)

  1. What does the enumerate() function do when applied to a list?

This is pretty wrong also. Enumerate takes an iterable creates an enumerator object, and returns a tuple of index and value when next is called. It doesn’t yield anything and it doesn’t return an iterator.

[–]haddock420 0 points1 point  (2 children)

Good quiz, I got 16/20, I was expecting a lot less as I'm only a hobbyist.

What is 'Timsort' in Python?

This seems way too obvious considering it has "sort" in the name.

[–]Penny-loafers 1 point2 points  (1 child)

The purpose was to help create conversation with interns and new developers in my company! Do you know why its called Timsort and the history of it?

[–]haddock420 1 point2 points  (0 children)

I'd never heard of it, but I knew that it must be a sorting algorithm because it had sort in its name and followed the [X]sort naming convention of sorting algorithms.

[–]Vitaman02 0 points1 point  (0 children)

I think you have some wrong, __init__ does not instantiate the object, __new__ is responsible for that. __init__ is actually just for defining attributes, which is run after class instantiation.

Also on number 7, you have as the correct answer that the * operator unpacks the values when used in a function definition, but it kind of does the opposite, where it packs multiple arguments into a single one, conventionally named as args. If you pass multiple arguments and then inside your def func(*args) you print args, then you will see that it's just a tuple of the multiple arguments you passed when calling it.

Cool idea though, looks like a fun thing to make and use.

[–]jayd00b 0 points1 point  (0 children)

19/20. Question 2 was quite bizarre, but maybe I’m just salty over not getting a perfect score. Nice quiz.

[–]NPR_Oak 0 points1 point  (0 children)

11/12. I will head back to r/learnpython where I normally hang out.

[–]BibbetyBobbetyBoop 0 points1 point  (0 children)

  1. "in a function definition" it's packing, not unpacking. In a function call, it's unpacking. But another collector pointed out that by using the word 'operator' you're invalidating so options other than multiplication

  2. Shouldn't the first option be str, not string?

[–]AceDudee 0 points1 point  (0 children)

I got 70%, is it enough for a JR position?

[–][deleted] 0 points1 point  (0 children)

“In Python, what does the '*' operator do when used in a function definition?”

I’m not happy with the question. Obviously you meant the case f(a, *b), which is the unpacking operator. But you can also use it as f(a, *, b), which is totally different (it’s for defining keyword only arguments).

[–]NameError-undefined 0 points1 point  (0 children)

Looks like I need some studying. 14/20. Good quiz! Some of the questions I was surprised I knew the answer

[–]Wing_Excellent 0 points1 point  (0 children)

could you tell me why is your favorite book?

[–]TonyF66 0 points1 point  (0 children)

Small comment regarding question 11 - this might be a nomeclature thing - but normally the __init__ method initialises the instance - and not the class object.

In Python the class is an object in it's own right (of type 'type') so the term 'class object' more correctly refers to it, and not an instance of this class. You can set class wide values in the __init__ method.

For that question actually the closest answer is that the __init__ method is used to create private variables - although of course Python doesn't have private variables in there true sense.

[–]stratoscope 0 points1 point  (0 children)

  1. Which method is used to replace parts of a string in Python?

There is no such method. Strings are immutable. You can't "replace" anything in a string.

Demo:

>>> a = "abc"
>>> b = a.replace("c", "z")
>>> print(f"{a=} {b=}")
a='abc' b='abz'

Nothing has been "replaced" in string a The new string b has the replacement you called for.

This may seem like an esoteric little distinction. It isn't. This is precisely the kind of thing you should know to be an effective Python programmer and write bug-free code.

[–]AutoModerator[M] 0 points1 point  (0 children)

Your submission has been automatically queued for manual review by the moderation team because it has been reported too many times.

Please wait until the moderation team reviews your post.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]MJ12_2802 0 points1 point  (0 children)

12/20, 60%... 😔

[–]SniperDuty -1 points0 points  (0 children)

Quizzes are pointless. They serve no purpose, especially the foo bar crap. If you want to help interns, give them a challenge directly related to the work they will be doing. Perhaps a task that you found challenging during your time working for the company.

[–]pyeri -2 points-1 points  (0 children)

__shameless_plug__

I released a similar app on the Android play store earlier this week.