Python: Quiz Questions Part 1

Python: Quiz Questions Part 1

ยท

7 min read

Good day,

Quiz Questions are a great way of practicing. Here are 5 questions focused around * and **. Take your time and don't just guess but think it through. So, understand that sometimes the answer is not the only way or might not be the best way. But hopefully you'll get an idea of a how the code is working. I know I learned a lot writing (and rewriting) the questions.

I also want to thank those that helped me with working on these questions.

Question 1. Using * in an assignment

In the below code, what's going to be printed?

# given this list
ages = [21, 4, 67, 13, 34]

a, *b, c = ages

# What will be printed?
print(a, c)

# 1) ValueError: too many values to unpack (expected 3)
# 2) 21 [67, 13, 34]
# 3) 21 34
# 4) [21, 4, 67, 13, 34], [21, 4, 67, 13, 34]

Question 2. Is this the same thing?

Let's look at a slightly different line but still looking at * as part of the assignment.

# What is this going to do?
*b, = 1, 2, 3

print(b)

# 1) 1
# 2) [1, 2, 3]
# 3) (1, 2, 3)
# 4) An Error - Do you know what 1 or 2 character(s) needs to be changed to fix it?

Question 3. Unpacking a dictionary

Let's flip to the other side of the assignment. What happens when we trying to unpack a dictionary into a list?

Let's look at using the * with a dictionary. What will be printed?

# with a dictionary 
states = {'California': 'Sacramento', 'Minnesota': 'St Paul', 'Georgia': 'Atlanta'}

results = [*states]

print(results)

# 1) ['California', 'Sacramento', 'Minnesota', 'St Paul', 'Georgia', 'Atlanta']
# 2) ['California', 'Minnesota', 'Georgia']
# 3) ['Sacramento', 'St Paul', 'Atlanta']
# 4) Syntax error, should be `**` not a single

Question 4. Combining two dictionaries

This question is a little different. You give the syntax required to give the output provided.

Using the update method of a dictionary lets you combine 2 dictionaries. Turns out it's possible to combine using dict as well.

# given these dictionaries
a = {'one': 1, 'three': 3}
b = {'two': 2, 'three': 'ha'}

# what do we put here
"""
d = dict(???)
print(d)
"""
# to get this?
# {'one': 1, 'three': 'ha', 'two': 2}

# 1) dict(a + b)
# 2) dict(a, b)
# 3) dict(a, **b)
# 4) dict(**a, **b)

Question 5 Zipping a dictionary

The built-in function zip is great for iterating over two lists at the same time. But what about a dictionary? We've seen * spread-out a dictionary. So what'll happen with this?

# What is going to be the first element?
states = {'California': 'Sacramento', 'Minnesota': 'St Paul', 'Georgia': 'Atlanta'}
x, *y = zip(*states.items())

print(x)

# 1) California
# 2) ('California', 'Minnesota', 'Georgia')
# 3) (('California', 'Sacramento'),)
# 4) ('California', 'Sacramento')

Answer 1

3) 21 34

What is happening here is called packing.

In the case of a, *b, c = ages, as ages is unpacked the first value is put in a, the last item is going into c, the rest will be placed in a list in b.

You might be familiar with it being used in the arguments of a function where we're packing all the arguments into nums, we're doing the almost exact same thing.

def myFunc(*nums):
    for num in nums:
       print(num)

One big difference is that nums will be a tuple but b will be a list.

With any assignment you need the proper number of values to match the number of variables. So how long does ages have to be? a and c need to be filled, but b doesn't. So, ages must be at least two values in length.

We could use this if we have the full name, but we want just the first name, and all the rest gets stored in rest_name.

name, *rest_name = 'Amanda S. C. Gorman'.split()

Answer 2

2) [1, 2, 3]

First is 1, 2, 3, we are used to some sort of brackets around a series of values. [] would be a list, () would be a tuple and {} would be a set or dictionary. But here's the kicker, you can define a tuple without the (). It's the , that is important.

For example

def myFunc():
    return 1, 2, 3

We might think about this is returning 3 values but it's not. It's returning a tuple of 3 values. The () aren't required! So, 1, 2, 3 in the assignment is a tuple.

Second is *b,. We're used to a comma separating two values. But there isn't a second one. While, back to tuples. We said () signify a tuple. So is (1) a tuple? Nope. It's just 1. We could use tuple(1). But we also could use the one thing that is required to define a tuple instead; ,. If we use (1,) it'll define a single value tuple. But we don't need to use () so drop those and 1, is a single value tuple!

We are unpacking the tuple 1, 2, 3 and packing it in a tuple *b,. Since this is a single item tuple it'll store 1, 2, 3 as a single value. But since we already seen the * go to a list, it'll convert the tuple to a list.

Yes, this *b, = 1, 2, 3 is another way to write b = list(1, 2, 3).

Because myFunc above returns a tuple, you could write.

*b, = myFunc()
b = list(myFunc())

And both of these lines do the same thing. Do you think you'll be using this? At least you won't be confused when you see it.

Answer 3

2) ['California', 'Minnesota', 'Georgia']

Like me, you may have been told that ** is for dictionary's and * is for tuples and lists. So what's happening here? The [] brackets is expecting a series of values and the * is expecting to iterate and spreadout some iterator. And what happens when you iterate over a dictionary? The keys are returned.

For example this will print the keys.

for state in states:
    print(state)

If we compare it to a list comparesion it lines up a bit better. I did some testing to see which is faster and while using * was slightly faster, but if you have a data set so large you can notice the difference, there is most likely other ways to speed your code up.

results = [state for state in states]
results = [*states]

Can a * with a dictionary be used in other places? Yep...

def myfunc(a, b, c):
    print(a, b, c)

myfunc(*states)

This will pass the 3 keys of states to the function myfunct('California', 'Minnesota', 'Georgia') and then print them.

Answer 4

3) dict(a, **b)

We can scratch off the a + b and a, b. Dictionaries don't use + and the dict only takes a single positional argument.

dict can accept a single dictionary and multiple key, value pairs and create a dictionary from that. So let's examine what ** does to a dictionary.

When dict(a, **b) is run, a will stay the same, a regular dictionary, and **b will expand out with the keys being the keyword argument and the value being the value:

dict({'one': 1, 'three': 3}, two= 2, three= 'ha')

Well, if **b* expands out, shouldn't we also be able to use **a as well? Let's see:

dict(one= 1, three= 3, two= 2, three= 'ha')

You might notice the issue. We can't pass the keyword argument three twice in. When the first three was in the dictionary it wasn't a keyword argument.

If there were no duplicate keys between the dictionaries, we could have used dict(**a, **b).

dict can take as many dictionaries as you want. In the below example b, c, d, and e cannot have duplicates of each other but will update the key if common in a.

combined = dict(a, **b, **c, **d, **e)

Answer 5

2) ('California', 'Minnesota')

Let's break this down:

states.items()

  • Provides a dict_items object that has tuples of each key/value pair.
dict_items([('California', 'Sacramento'), ('Minnesota', 'St Paul'), ('Georgia', 'Atlanta')])`

*states.items()

  • Spreads the tuples of key/value pair out.
('California', 'Sacramento')
('Minnesota', 'St Paul')
('Georgia', 'Atlanta')

zip(*states.items())

  • Takes the matching element (by position) of each tuple and passes them as a tuple.
('California', 'Minnesota', 'Georgia')
('Sacramento', 'St Paul', 'Atlanta')

What we end up with is two tuples, one with the keys and the second with the values.

In case you're curious, these are the statements that form the other answers.

  • 1) x, *y = states
  • 3) x, *y = zip(states.items())
  • 4) x, *y = *states.items(),

Resources

These sites are some of the sites I used while writing this.

Did you find this article valuable?

Support Russ Eby by becoming a sponsor. Any amount is appreciated!