Iterables
Sequences
1. Explain the data type sequence.
A sequence is an ordered collection of elements, where each element is identified by an index or a key
2. Provide an example of homogeneous and heterogeneous sequences.
- Homogeneous: String because each element is of the same type (a character)
- Heterogeneous: Lists because each element can be of different types.
3. What is required for an object to be iterable?
A container type of object that can list out of the elements one by one.
4. Can a sequence be considered an iterable? Conversely, can an iterable be regarded as a sequence?
Any sequence type is iterable but not all iterables is a sequence type. Iterables are more general, there is no need for positional ordering such as sets.
5. When copying another tuple (t2=t1), will t2 have a different memory address than t2? Explain your answer.
It will have the same memory address because tuples are immutable.There is no point in creating a new memory address when the tuple data structure will be the same.
6. Why is tuple more efficient than lists?
In general, tuple is more efficient because of its immutability property. When objects are immutable they are more memory efficient, the interpreter can make certain memory optimisations, and multiple references to the same tuple can share the same memory address.
7. Does lst.copy() return a new object? How about the elements in the list lst?
Copying a list returns a new object. However, the elements in the list that have been copied are the same objects.
8. lst2 is a copy of lst1. What happens to the elements in lst1 when we modify the elements in lst2? Assume that the elements are mutable.
If the element is mutable, when we modify either of the list’s element, both will reflect the change. This indicates that the elements in
lst1 will be updated to.
9. Why is it a good practice to copy mutable sequences before modifying the internal state (data)?
Modifying a sequence in-place can lead to unintended side effects, especially when the same sequence is referenced in multiple places in the code. Copying ensures that the original data remains unchanged. This is crucial for maintaining data integrity, especially when the original data is needed elsewhere or should be preserved.
10. Define shallow copy in the context of the container (list) object reference and the elements.
Returning the copy of the original sequence and all the object references, which means the copy container has a different object reference but the elements will have the same memory addresses as the original sequence elements.
11. Explain the purpose of performing deep copy.
To copy an object such that it will modifications in the copy will not affect the original even if the original object contains mutable objects.
12. How does deep copy works?
To copy the original object recursively to copy the nested elements in the object.
13. Explain the difference between concatenation (+) and in-place concatenation (+=) in combining two lists.
- Concatenation creates a new list combining both elements of both lists.
- In-place concatenation mutates the original list, this means that the list retains the same object reference.
14. Explain the difference between concatenation (+) and in-place concatenation (+=) in combining two tuples.
- Concatenation creates a new list combining both elements of both tuples.
- In-place concatenation will also create a new object reference because tuples are immutable.
Iterators
1. Explain iterators.
An iterator is an object that allows you to iterate over collections of data, such as lists, tuples, dictionaries, and sets.
2. What are three main actions an iterator performs?
- Return the next item from a stream or container sequentially.
- Keeping track of the current and visited items.
- Stop iterating when it reaches to the length of the sequence.
3. Explain the Iterator Protocol’s two special method.
An object in Python is recognised as an iterator when it collectively incorporates two specific methods, known together as the iterator protocol.
__iter__: Called to initialise the iterator. Returns the iterator object itself.__next__: Called to iterate over the iterator and raise theStopIterationexception when all elements have been exhausted.
4. Explain the differences between iterable and iterator.
- An iterable is an object with an
__iter__()method, and it can be looped over using aforloop. - An iterator is an iterable with an additional
__next__()method, allowing it to fetch the next element in the sequence.
To summarise, the iterable is the collection while the iterator is responsible for iterating over the iterable/ collection
5. Is every iterator also an iterable?
Every iterator is also an iterable, but not every iterable is an iterator in Python.
6. Where does python use iterators?
Python uses iterators to support every operation that requires iteration, including for loops, comprehensions,
7. Are iterators exhaustive?
Yes, iterators are exhaustive, meaning once we implement an iterator, we no longer can reuse it again.
8. Explain the parameters iter(iterable, sentinel).
iter(): The function returns an iterator object.iterable: The collection to iterate over.sentinel (optional): If provided, it defines a stopping condition for the iterator. The iterator will keep calling__next__()method until the value returned matches thesentinel.
9. Explain aggregators.
Functions that iterate through an iterable and return a single value that usually takes into account every element of the iterable.
10. Explain any(iterable).
Returns
True if any (one or more) element in iterable is evaluated as True / truthy.
11. Explain all(iterable).
Returns
True only if all the elements in iterables are truthy
12. Define predicate functions.
A function that takes a single argument and returns True or False is called a predicate.
13. What is the use-case of applying predicate in the context or any() or all().
Apply predicate function to every element of the iterable to get the associated truths and then we are able to use
any() or all() on the results.
14. How to apply predicate evaluation to an iterable?
# Use the map function.
pred = map(func, iterable)
Generators
1. Explain the concept of lazy iterables.
Do not have to get next item in an iterable until it is actually requested.
2. Explain the keyword next(iterable)
Retrieves the next item from an iterable one at a time.
3. Describe the process of calling a function that has a yield statement.
- It emits a value and the function is effectively suspended (not terminated).
- Calling next on the function resumes running the function right after the
yieldstatement. - If there are no more yields (exhausted), the function will return a value, if the value is not specified it will return
None, which terminates the function.
4. Explain generators (generator function).
A function that uses the
yield statement is called the generator function. When called, a generator function returns a generator object, which is an iterator.
5. Explain the main use case of a generator function.
Generator function allows you to iterate over a potentially large sequence of values without creating the entire sequence in memory at once.
6. Explain the key difference between yield and return upon encountering the statements.
yieldretains the current state of the function, the local scope still exists.returnexits the function and destroys the local scope.
7. Are generators lazy iterators? Explain your answer.
Generators are lazy iterators because they only perform
next when requested.