2 ** 16

2 / 5, 2 / 5.0

"spam" + "eggs"

S = "ham"
"eggs " + S

S * 5

S[:0]

"green %s and %s" % ("eggs", S)

'green {0} and {1}'.format('eggs', S)

('x',)[0]

('x', 'y')[1]

L = [1,2,3] + [4,5,6]
L, L[:], L[:0], L[-2], L[-2:]

([1,2,3] + [4,5,6])[2:4]

[L[2], L[3]]

L.reverse(); L

L.sort(); L

L.index(4)

{'a':1, 'b':2}['b']

D = {'x':1, 'y':2, 'z':3}
D['w'] = 0
D

D['x'] + D['w']
D

D[(1,2,3)] = 4
D

list(D.keys()), list(D.values()), (1,2,3) in D

[[]], ["",[],(),{},None]

"""
Explanation: Test your knowledge: Part II exercises
1. The basics
Run each of the following expressions, and try to
explain what’s happening in each case. Note that the semicolon in some of these
is being used as a statement separator, to squeeze multiple statements onto a single
line: for example, X=1;X assigns and then prints a variable. Also remember that a comma between expressions usually builds a tuple, even if there are no enclosing parentheses: X,Y,Z
is a three-item tuple, which Python prints back to you in parentheses.
End of explanation
"""


X = 'spam'
Y = 'eggs'
X, Y = Y, X

"""
Explanation: 2. Indexing and slicing
At the interactive prompt, define a list named L that contains
four strings or numbers (e.g., L=[0,1,2,3] ). Then, experiment with the following
boundary cases. You may never see these cases in real programs (especially not in
the bizarre ways they appear here!), but they are intended to make you think about
the underlying model, and some may be useful in less artificial forms—slicing out
of bounds can help, for example, if a sequence is as long as you expect:
- What happens when you try to index out of bounds (e.g., L[4] )?
- What about slicing out of bounds (e.g., L[−1000:100] )?
- Finally, how does Python handle it if you try to extract a sequence in reverse,
with the lower bound greater than the higher bound (e.g., L[3:1] )? Hint: try
assigning to this slice ( L[3:1]=['?'] ), and see where the value is put. Do you
think this may be the same phenomenon you saw when slicing out of bounds?
3. Indexing, slicing and del
Define another list L with four items, and assign an empty
list to one of its offsets (e.g., L[2]=[] ). What happens? Then, assign an empty list
to a slice ( L[2:3]=[] ). What happens now? Recall that slice assignment deletes the
slice and inserts the new value where it used to be.
The del statement deletes offsets, keys, attributes, and names. Use it on your list
to delete an item (e.g., del L[0] ). What happens if you delete an entire slice ( del
L[1:] )? What happens when you assign a nonsequence to a slice ( L[1:2]=1 )?
4. Tuple assignment
What do you think is happening to X and Y when you run following sequence?
End of explanation
"""


D = {}
D[1] = 'a'
D[2] = 'b'
D

"""
Explanation: 5. Dictionary keys.
You’ve learned that dictionaries aren’t accessed by offsets, so what’s going on here?
End of explanation
"""


D[(1, 2, 3)] = 'c'
D

"""
Explanation: Does the following shed any light on the subject? (Hint: strings, integers, and tuples
share which type category?)
End of explanation
"""


!ls

"""
Explanation: 6. Dictionary indexing.
Create a dictionary named D with three entries, for keys 'a' ,
'b' , and 'c' . What happens if you try to index a nonexistent key ( D['d'] )? What
does Python do if you try to assign to a nonexistent key 'd' (e.g., D['d']='spam' )?
How does this compare to out-of-bounds assignments and references for lists?
Does this sound like the rule for variable names?
7. Generic operations.
Run interactive tests to answer the following questions:
- What happens when you try to use the + operator on different/mixed types
(e.g., string + list, list + tuple)?
- Does + work when one of the operands is a dictionary?
- Does the append method work for both lists and strings? How about using the
keys method on lists? (Hint: what does append assume about its subject object?)
- Finally, what type of object do you get back when you slice or concatenate two
lists or two strings?
8. String indexing.
Define a string S of four characters: S = "spam" . Then type the
following expression: S[0][0][0][0][0] . Any clue as to what’s happening this time?
(Hint: recall that a string is a collection of characters, but Python characters are
one-character strings.) Does this indexing expression still work if you apply it to a
list such as ['s', 'p', 'a', 'm'] ? Why?
9. Immutable types.
Define a string S of four characters again: S = "spam" . Write an
assignment that changes the string to "slam" , using only slicing and concatenation.
Could you perform the same operation using just indexing and concatenation?
How about index assignment?
10. Nesting.
Write a data structure that represents your personal information: name
(first, middle, last), age, job, address, email address, and phone number. You may
build the data structure with any combination of built-in object types you like (lists,
tuples, dictionaries, strings, numbers). Then, access the individual components of
your data structures by indexing. Do some structures make more sense than others
for this object?
11. Files
Write a script that creates a new output file called myfile.txt and writes the
string "Hello file world!" into it. Then write another script that opens my-
file.txt and reads and prints its contents. Does the new file show up in the directory where you ran your
scripts? What if you add a different directory path to the filename passed to open ?
Note: file write methods do not add newline characters to your strings; add an
explicit \n at the end of the string if you want to fully terminate the line in the file.
End of explanation
"""


for i in range(5):
    print('hello %d\n\a' % i, end="")

"""
Explanation: Test your knowledge: Part III exercises
1. Coding basic loops

Write a for loop that prints the ASCII code of each character in a string named S. Use the built-in function ord(character) to convert each character to an
ASCII integer. This function technically returns a Unicode code point in
Python 3.X, but if you restrict its content to ASCII characters, you’ll get back
ASCII codes. (Test it interactively to see how it works.)
Next, change your loop to compute the sum of the ASCII codes of all the
characters in a string.
Finally, modify your code again to return a new list that contains the ASCII
codes of each character in the string. Does the expression map(ord, S) have a
similar effect? How about [ord(c) for c in S] ? Why? (Hint: see Chapter 14.)

2. Backslash characters
What happens on your machine when you type the following
code interactively?
End of explanation
"""


def f1(a, b): print(a, b)    # Normal args
def f2(a, *b): print(a, b)   # Positional varargs
def f3(a, **b): print(a, b)  # Keyword varargs
def f4(a, *b, **c): print(a, b, c)  # Mixed modes
def f5(a, b=2, c=3): print(a, b, c) # Defaults
def f6(a, b=2, *c): print(a, b, c)  # Defaults and positional varargs

"""
Explanation: 3. Sorting dictionaries.
In Chapter 8, we saw that dictionaries are unordered collections. Write a for loop that prints a dictionary’s items in sorted (ascending) order. (Hint: use the dictionary keys and list sort methods, or the newer sorted built-in function.)
4. Program logic alternatives.
Consider the following code, which uses a while loop and found flag to search a list of powers of 2 for the value of 2 raised to the fifth power (32).
```python
L = [1, 2, 4, 8, 16, 32, 64]
X = 5
found = False
i = 0
while not found and i < len(L):
    if 2 ** X == L[i]:
        found = True
    else:
        i = i+1
if found:
    print('at index', i)
else:
    print(X, 'not found')     
```
As is, the example doesn’t follow normal Python coding techniques. Follow the steps outlined here to improve it:
- First, rewrite this code with a while loop else clause to eliminate the found flag and final if statement.
- Next, rewrite the example to use a for loop with an else clause, to eliminate the explicit list-indexing logic. (Hint: to get the index of an item, use the list index method— L.index(X) returns the offset of the first X in list L .)
- Next, remove the loop completely by rewriting the example with a simple in operator membership expression. (See Chapter 8 for more details, or type this to test: 2 in [1,2,3] .)
- Finally, use a for loop and the list append method to generate the powers-of-2 list ( L ) instead of hardcoding a list literal.
Deeper thoughts:
- Do you think it would improve performance to move the 2 ** X expression outside the loops? How would you code that?
- As we saw in exercise 1, Python includes a map(function, list) tool that can generate a powers-of-2 list, too: map(lambda x: 2 ** x, range(7)). Try typing this code interactively; we’ll meet lambda more formally in the next part of this book, especially in Chapter 19. Would a list comprehension help here (see Chapter 14)?
5. Code maintenance.
If you haven’t already done so, experiment with making the code changes suggested in this chapter’s sidebar “Changing PyDoc’s Colors” on page 456. Much of the work of real software development is in changing existing code, so the sooner you begin doing so, the better. For reference, my edited copy of PyDoc is in the book’s examples package, named mypydoc.py; to see how it differs, you can run a file compare (fc on Windows) with the original pydoc.py in 3.3 (also included, lest it change radically in 3.4 as the sidebar describes). If PyDoc is more easily customized by the time you read these words, customize colors per its current convention instead; if this involves changing a CSS file, let’s
hope the procedure will be well documented in Python’s manuals.
Test Your Knowledge: Part IV Exercises
1. The basics.
At the Python interactive prompt, write a function that prints its single
argument to the screen and call it interactively, passing a variety of object types:
string, integer, list, dictionary. Then, try calling it without passing any argument.
What happens? What happens when you pass two arguments?
2. Arguments.
Write a function called adder in a Python module file. The function
should accept two arguments and return the sum (or concatenation) of the two.
Then, add code at the bottom of the file to call the adder function with a variety of
object types (two strings, two lists, two floating points), and run this file as a script
from the system command line. Do you have to print the call statement results to
see results on your screen?
3. varargs.
Generalize the adder function you wrote in the last exercise to compute
the sum of an arbitrary number of arguments, and change the calls to pass more
or fewer than two arguments. What type is the return value sum? (Hints: a slice
such as S[:0] returns an empty sequence of the same type as S , and the type built-
in function can test types; but see the manually coded min examples in Chapter 18 for a simpler approach.) What happens if you pass in arguments of different
types? What about passing in dictionaries?
4. Keywords.
Change the adder function from exercise 2 to accept and sum/concatenate three arguments: def adder(good, bad, ugly). Now, provide default values
for each argument, and experiment with calling the function interactively. Try
passing one, two, three, and four arguments. Then, try passing keyword arguments. Does the call adder(ugly=1, good=2) work? Why? Finally, generalize the
new adder to accept and sum/concatenate an arbitrary number of keyword arguments. This is similar to what you did in exercise 3, but you’ll need to iterate over
a dictionary, not a tuple. (Hint: the dict.keys method returns a list you can step
through with a for or while , but be sure to wrap it in a list call to index it in 3.X;
dict.values may help here too.)
5. Dictionary tools.
Write a function called copyDict(dict) that copies its dictionary
argument. It should return a new dictionary containing all the items in its argument. Use the dictionary keys method to iterate (or, in Python 2.2 and later, step
over a dictionary’s keys without calling keys ). Copying sequences is easy ( X[:]
makes a top-level copy); does this work for dictionaries, too? As explained in this
exercise’s solution, because dictionaries now come with similar tools, this and the
next exercise are just coding exercises but still serve as representative function
examples.
6. Dictionary tools.
Write a function called addDict(dict1, dict2) that computes the
union of two dictionaries. It should return a new dictionary containing all the items
in both its arguments (which are assumed to be dictionaries). If the same key appears in both arguments, feel free to pick a value from either. Test your function
by writing it in a file and running the file as a script. What happens if you pass lists
instead of dictionaries? How could you generalize your function to handle this case,
too? (Hint: see the type built-in function used earlier.) Does the order of the arguments passed in matter?
7. More argument-matching examples.
End of explanation
"""


f1(1, 2)

f1(b=2, a=1)

f2(1, 2, 3)

f3(1, x=2, y=3)

f4(1, 2, 3, x=2, y=3)

f5(1)

f5(1, 4)

f6(1)

f6(1, 3, 4)

"""
Explanation: Test the following calls interactively, and try to explain each result; in some
cases, you’ll probably need to fall back on the matching algorithm shown in Chapter 18. Do you think mixing matching modes is a good idea in general? Can you think of cases where it would be useful?
End of explanation
"""


