python cookbook Chapter 1, sections 1-2
1.1 the decompression sequence is assigned to multiple variables
Question: now there is a tuple or sequence containing N elements. How to decompress its value and assign it to N variables at the same time?
Solution any sequence (or iteratable object) can be decompressed and assigned to multiple variables through a simple assignment statement. The only premise is that the number of variables must be the same as the number of sequence elements.
p = (4, 5) x, y = p x #4 y #5
data = [ 'ACME', 50, 91.1, (2012, 12, 21) ] name, shares, price, date = data name #'ACME' date #(2012, 12, 21) name, shares, price, (year, mon, day) = data name #'ACME' year #2012 mon #12 day #21
If the number of variables does not match the number of sequence elements, an exception will be generated.
p = (4, 5) x, y, z = p #ValueError: not enough values to unpack (expected 3, got 2)
In fact, this decompression assignment can be used on any iteratable object, not just lists or tuples. Includes strings, file objects, iterators, and generators.
s = 'Hello' a, b, c, d, e = s a #'H' b #'e' e #'o'
Sometimes, you may just want to unzip a part and discard other values. In this case, Python does not provide a special syntax. But you can use any variable name to occupy the space, and then you can just throw away these variables.
data = [ 'ACME', 50, 91.1, (2012, 12, 21) ] _, shares, price, _ = data shares #50 price #91.1
You must ensure that the placeholder names you choose are not used elsewhere.
1.2 decompress the iteratable object and assign it to multiple variables
Problem: if the number of elements of an iteratable object exceeds the number of variables, a ValueError will be thrown. So how do I extract N elements from this iteratable object?
Solution: Python's asterisk expression can be used to solve this problem.
For example, you are studying a course. At the end of the semester, you want to count the average score of homework, but exclude the first and last scores. If there are only four scores, you may simply assign them manually, but what if there are 24? At this time, the asterisk expression comes in handy:
def drop_first_last(grades): first, *middle, last = grades return avg(middle)
In another case, suppose you now have a list of users' records. Each record contains a name, email, and then an uncertain number of phone numbers. You can break down these records as follows:
record = ('Dave', 'firstname.lastname@example.org', '773-555-1212', '847-555-1212') name, email, *phone_numbers = record name #'Dave' email #email phone_numbers #['773-555-1212', '847-555-1212']
It is worth noting that the phone extracted above_ The numbers variable is always a list type, regardless of the number of phone numbers decompressed (including 0). So, any use of the phone_ The code of the numbers variable does not need to do extra type checking to confirm whether it is a list type.
The asterisk expression can also be used at the beginning of the list. For example, you have a sequence of the company's sales data for the first eight months, but you want to see the comparison between the data of the last month and the average value of the previous seven months. You can do this:
*trailing_qtrs, current_qtr = sales_record trailing_avg = sum(trailing_qtrs) / len(trailing_qtrs) return avg_comparison(trailing_avg, current_qtr)
The following is the result of execution in the Python interpreter:
*trailing, current = [10, 8, 7, 1, 9, 5, 10, 3] #Bits of all unoccupied elements trailing #[10, 8, 7, 1, 9, 5, 10] current #3
The extended iterative decompression syntax is specially designed to decompress iteratable objects with uncertain or arbitrary number of elements. Generally, the element structure of these iteratable objects has certain rules (for example, the first element is followed by a phone number). The asterisk expression allows developers to easily extract the elements by using these rules. Instead of obtaining these associated element values through some complex means.
It is worth noting that the asterisk expression is useful when iterating over sequences whose elements are variable length tuples. For example, the following is a tuple sequence with labels:
records = [ #Tuple sequence with label ('foo', 1, 2), ('bar', 'hello'), ('foo', 3, 4), ] def do_foo(x, y): print('foo', x, y) def do_bar(s): print('bar', s) for tag, *args in records: if tag == 'foo': do_foo(*args) elif tag == 'bar': do_bar(*args)
foo 1 2
foo 3 4
The asterisk decompression syntax is also useful in string operations, such as string segmentation.
line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false' uname, *fields, homedir, sh = line.split(':') uname #'nobody' homedir #'/var/empty' sh #'/usr/bin/false'
Sometimes you want to unzip some elements and discard them. You can't simply use *, but you can use a common obsolete name, such as_ Or ign ore.
record = ('ACME', 50, 123.45, (12, 18, 2012)) name, *_, (*_, year) = record name #'ACME' year #2012
In many functional languages, the asterisk decompression syntax has many similarities with list processing. For example, if you have a list, you can easily divide it into two parts:
items = [1, 10, 7, 4, 5, 9] head, *tail = items head #1 tail #[10, 7, 4, 5, 9]
If you are smart enough, you can use this segmentation syntax to skillfully implement the recursive algorithm. For example:
def sum(items): head, *tail = items return head + sum(tail) if tail else head sum(items)
However, due to language level constraints, recursion is not good at Python. Therefore, the last recursive demonstration is just a curious exploration. Don't take this too seriously.