# CS 1358 Introduction to Programming in Python SC12
###### tags: `pythonSC`
# Definitions and Short Answers - functions
1. Given a for loop:
```python
for i in L:
print(i)
```
Can L be the following? If so, what does the loop print? If not, why not?
- [X] ['a', 'b', 'c']
- [X] ('a', 'b', 'c')
- [X] 'abc'
- [X] {'a', 'b', 'c'}
- [X] {'a': 100, 'b': 200, 'c': 300}
- [ ] 0xabcd
- [X] range(3)
- [ ] 23+4j
2. Given an iterable data structure L
a. How do you obtain an iterator r of L?
> r = iter(L)
b. Once you have an iterator r, what can you do to get the next value?
> next\(r\)
c. What happens when you call next(r) but your iterator r has finished iterating over all values of L?
> StopIteration
d. Is there a limit to the number of iterators that you can create on the same iterable?
> No
3. Assume you have
```python=
D = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
r = iter(D)
L = [next(r) for i in range(3)]
s = iter(D)
M = [next(s) for i in range(2)]
```
after executing these five lines
a. What is the value of L?
```
['Sun', 'Mon', 'Tue']
```
b. What is the value of M?
```
['Sun', 'Mon']
```
c. What is the value of D?
```
['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
```
4. Recall the Vector class from the previous lecture
```python=
import operator as op
class Vector:
def __init__(self, *v):
self._v = list(v) # covert tuple to list
def __repr__(self):
return __class__.__name__+repr(tuple(self._v))
```
Suppose a class defines an \_\_iter__() special method, and v is an instance of Vector.
a. How does Python intend that v's \_\_iter__() special method be invoked by the programmer? Hint: not v.\_\_iter__()
> modify \_\_getitem__()
b. What kind of object should the \_\_iter__() method return?
> custom iterator class
c. What is one simple way to implement Vector's \_\_iter__() method, given that the iterator for Vector would essentially be the same as the iterator for the list self._v ?
> return list_iterator(self)
5. An alternative to part 4.(c) is to define a class for VectorIterator, and Vector's \_\_iter__() method would instantiate and return it. The code is as follows:
```python=
class Vector:
def __iter__(self):
return Vector_Iterator(self):
class VectorIterator:
def __init__(self, vec):
self._vec = vec
self._i = 0
def __next__(self):
if self._i >= len(self._vec):
raise StopIteration
val = self._vec[self._i]
self._i += 1
return val
```
a. In VectorIterator's constructor, what is the purpose of initializing _i = 0?
> to initialize the position
b. Why does VectorIterator's constructor need to set its _vec attribute to the iterable? Why isn't it enough to just keep track of its position _i?
> 這樣他next()的時候 就沒有辦法回傳資料了阿
c. How does Python intend that the \_\_next__() method of a VectorIterator instance vi be invoked? Hint: not vi.\_\_next__()
> next(vi)
d. How does \_\_next__() special method indicate that it has finished iterating all elements?
> When i larger than len(self._vec) raise StopIteration
6. Assume Vector is iterable, rewrite the following for-loop using a while loop and explicit iter() instantiation, next(), and catching StopIteration exception:
```python=
v = Vector(7, 1, 4, 3, 9, 6, 5)
i = iter(v)
while True:
try:
print(next(i), end = '')
except StopIteration:
break
```
7. Can any iterable object v be passed as arguments to
- [x] list(v)
- [x] max(v)
8. For the Blackjack game example, Card is declared as a class:
```python=
class Class:
ACE, JACK, QUEEN, KING = 'A', 'J', 'Q', 'K'
FACES = (ACE,2,3,4,5,6,7,8,9,10, JACK, QUEEN, KING)
SUITS = tuple(map(chr, (9824, 9827, 9829, 9830)))
SPADE, CLUB, HEART, DIAMOND = SUITS # ♠ ♣ ♥ ♦
def __init__(self, suit, face):
self._suit = suit
self._face = face
def __int__(self):
if self._face in {Card.JACK,Card.QUEEN,Card.KING}:
return 10
return 1 if self._face == Card.ACE else self._face
def __str__(self):
return self._suit + str(self._face)
def __repr__(self):
return __class__.__name__ + \
repr((self._suit, self._face))
```
a. Why is it a good practice to declare class attributes such as SPADE, CLUB, HEART, and DIAMOND even though Python3 handles unicode character literals such as '♠' '♣' '♥' '♦'.
> It can't be an identifer.
b. What is the purpose of special method \_\_int__()?
> For returning the value of the card.
c. Why declare a \_\_str__() special method even though \_\_repr__() also exists and can make a string that represents the card?
> 為了支援str()這個built-in function
d. Is Card class iterable? Should it be iterable?
> No, it didn't define \_\_iter()__
e. Is Card class for instantiating iterators?
> No
9. Continuing with the BlackJack example, a separate class named Deck is also declared.
```python=
class Deck:
def __init__(self):
self._deck = [Card(suit, face) \
for suit in Card.SUITS for face in Card.FACES]
def shuffle(self):
import random
random.shuffle(self._deck)
def __iter__(self):
return iter(self._deck)
```
a. Is Deck an iterable? If so, is it required to implement the \_\_getitem__() special method?
> Yes, No
b. Explain how the Deck class is able to create iterators by simply returning iter(self._deck) from its \_\_iter__() special method. Explain why this works.
> ._deck is a list, list is iterable.
10. In Single-player BlackJack,
```python=
def BlackJack():
D = Deck()
D.shuffle()
total = 0
it = iter(D)
while True:
c = next(it)
total += int(c)
print(f'your card: {c}, total = {total}.', end='')
if total > 21:
print(f'you lose! total = {total}')
break
if total == 21:
print(f'you win! total = 21')
break
ans = input('More cards? [y/n] ')
if ans not in 'Yy':
c = next(it) # draw one more to test
print(f'next card {c}. You ' +\
('win' if total + c > 21 else 'lose'))
break
```
a. What kind of object is it as created on line 6?
> The iterator of Deck (list_iterator)
b. What kind of object is returned by a call to next(it) on line 7 or 18?
> Card
c. Why doesn't this program have to handle the case where the iterator raises StopIteration exception when the deck is empty?
> Use the list_iterator which help tp handle thx exceptioin
11. Is the following a function or a generator?
- [x] a
```python
def X(z):
for i in range(20):
yield i
```
- [ ] b
```python
def Y(z):
for i in range(20):
return i
```
- [x] c
```python
def K(z):
for i in range(20):
yield i
return -1
```
12. if fib() is a generator for Fibonacci numbers, what is the syntax for
```python=
g = fib() # instantiate generator
init_num = next(g)
print('initial number = ', init_num)
for i in range(10):
num = next(g)
print(num)
```
13. Assume g = fib() is a generator for Fibonacci numbers, and r = iter(deck) is an iterator where deck is an instance of iterable class Deck Which of the following are allowed?
- [x] a. list\(r\)
- [x] b. list(g)
- [x] c. list(fib())
- [x] d. list(deck)
- [x] e. [i for i in r]
- [x] f. [i for i in g]
- [x] g. [i for i in fib()]
- [x] h. [i for i in iter(deck)]
- [x] i. next\(r\)
- [x] j. next(g)
- [ ] k. x, y, z = deck
- [ ] l. x, y, z = fib()
- [ ] m. x, y, z = g
- [ ] n. x, y, z = r