14 min read

Learn Python The Hard Way 读书笔记


通过将本书里的每一个例子一字不差地打出来,你将通过实践训练自己,让自己集中 精力到你作品的细节上面。

虽然对这点我不苟同。

Copyright (C) 2010 by Zed A. Shaw. 你可以在不收取任何费用,而且不修改任何内容 的前提下自由分发这本书给任何人。但是本书的内容只允许完整原封不动地进行分发和传 播。也就是说如果你用这本书给人上课,只要你不向学生收费,而且给他们看的书是完整 未加修改的,那就没问题。


准备工作

这里先说Win7的,OSX的之后再说。

开始打开PowerShell,开始打开Python了,输入python小写。 退出python的方法是Ctrl+z再回车,回到上面那一步的操作。

现在的问题是无法复制命令框的代码。

在Powershell顶端右键\(\to\)编辑,可以查看到复制是灰色的,表示默认,并且发现快捷方式是回车键,因此只要用鼠标,点击左键,选中代码框中需要的代码,然后点击回车,代码就复制好了。

PS C:\Users\lijiaxiang> cd myfolder
PS C:\Users\lijiaxiang\myfolder>

… 使用 Notepad++ 编辑 myfolder 目录下的 test.txt

PS C:\Users\lijiaxiang\myfolder> ls


    目录: C:\Users\lijiaxiang\myfolder


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         2018/1/10     16:56          4 test.txt

OSX中安装TextWrangler

TextWrangler is now part of BBEdit. We have sunsetted TextWrangler, and BBEdit has changed to make room for TextWrangler users.

因此安装,BBEdit

好麻烦,直接用微软的Visual Studio Code好了。

习题1: python xxx.py

print("Hello World!")
print("Hello Again")
print("I like typing this.")
print("this is fun.")
print('Yay! Printing.')
print("I'd much rather you 'not'.")
print('I "said" do not touch this.')

这是Python的代码,注意,"'是相互套用。

PS C:\Users\lijiaxiang\myfold
Hello World!
Hello Again
I like typing this.
this is fun.
Yay! Printing.
I'd much rather you 'not'.
I "said" do not touch this.

习题3: 运算符号

print("I will now count my chickens:")

print("Hens", 25 + 30/6)
print("Roosters", 100 - 25 * 3 % 4)

print("Now I will count the eggs:")

print(3 + 2 + 1 - 5 + 4 % 2 - 1/4 + 6)

print("Is it true that 3 + 2 < 5 -7?")

print(3+2<5-7)

print("What is 3+2?", 3+2)
print("WHat is 5-7?", 5-7)

print("Oh, that's why it's False.")

print("How about some more.")

print("Is it greater?", 5 > -2)
print("Is it greater or equal?", 5 >= -2)
print("Is it less or equal?", 5 <= -2)

%的解释。 返回除法的余数。

PS C:\Users\lijiaxiang\myfolder> python ex3.py
I will now count my chickens:
Hens 30.0
Roosters 97
Now I will count the eggs:
6.75
Is it true that 3 + 2 < 5 -7?
False
What is 3+2? 5
WHat is 5-7? -2
Oh, that's why it's False.
How about some more.
Is it greater? True
Is it greater or equal? True
Is it less or equal? False

习题4: 变量

cars = 100
space_in_a_car = 4.0
drivers = 30
passengers = 90
cars_not_driven = cars - drivers
cars_driven = drivers
carpool_capacity = cars_driven * space_in_a_car
average_passengers_per_car = passengers / cars_driven


print("There are", cars, "cars available.")
print("There are only", drivers, "drivers available.")
print("There will be", cars_not_driven, "empty cars today.")
print("We can transport", carpool_capacity, "people today.")
print("We have", passengers, "to carpool today.")
print("We need to put about", average_passengers_per_car, "in each car.")
PS C:\Users\lijiaxiang\myfolder> python ex4.py
There are 100 cars available.
There are only 30 drivers available.
There will be 70 empty cars today.
We can transport 120.0 people today.
We have 90 to carpool today.
We need to put about 3.0 in each car.

习题5: 字符串的变量

#是注释。 %s是字符串的变量。通过% variable来衡量。 可以用(var1, var2)来完成两个变量的引用。

my_name = 'Zed A. Shaw'
my_age = 35 # not a lie
my_height = 74 # inches
my_weight = 180 # lbs
my_eyes = 'Blue'
my_teeth = 'White'
my_hair = 'Brown'

print("Let's talk about %s." % my_name)
print("He's %d inches tall." % my_height)
print("He's %d pounds heavy." % my_weight)
print("Actually that's not too heavy.")
print("He's got %s eyes and %s hair." % (my_eyes, my_hair))
print("His teeth are usually %s depending on the coffee." % my_teeth)

# this line is tricky, try to get it exactly right
print("If I add %d, %d, and %d I get %d." % (
my_age, my_height, my_weight, my_age + my_height + my_weight))
PS C:\Users\lijiaxiang\myfolder> python ex5.py
Let's talk about Zed A. Shaw.
He's 74 inches tall.
He's 180 pounds heavy.
Actually that's not too heavy.
He's got Blue eyes and Brown hair.
His teeth are usually White depending on the coffee.
If I add 35, 74, and 180 I get 289.

习题6: %和打印

x = "There are %d types of people." % 10
binary = "binary"
do_not = "don't"
y = "Those who know %s and those who %s." % (binary, do_not)

print(x)
print(y)

print("I said: %r." % x)
print("I also said: '%s'." % y)


hilarious = False
joke_evaluation = "Isn't that joke so funny?! %r"

print(joke_evaluation % hilarious)

w = "This is the left side of..."
e = "a string with a right side."

print(w + e)

注意这里 y = "Those who know %s and those who %s." % (binary, do_not) y可以直接这样定义。

PS C:\Users\lijiaxiang\myfolder> python ex6.py
There are 10 types of people.
Those who know binary and those who don't.
I said: 'There are 10 types of people.'.
I also said: 'Those who know binary and those who don't.'.
Isn't that joke so funny?! False
This is the left side of...a string with a right side.

习题8: %r的认识

The %s specifier converts the object using str(), and %r converts it using repr().

%r更像是raw data。

举例,

months = "\nJan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug"
print("Here are the months: %r" % months)
print("Here are the months: %s" % months)
PS C:\Users\lijiaxiang\myfolder> python .\ex7_pre.py
Here are the months: '\nJan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug'
Here are the months:
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug

%r真的会把\n打印出来。

习题10: """\t的使用

tabby_cat = "\tI'm tabbed in."
persian_cat = "I'm split\non a line."
backslash_cat = "I'm \\ a \\ cat."

fat_cat = """
I'll do a list:
\t* Cat food
\t* Fishies
\t* Catnip\n\t* Grass
"""

print(tabby_cat)
print(persian_cat)
print(backslash_cat)
print(fat_cat)

学习这个地方\t的使用方法。

并且在Notepad++中,有很好的结构,如图。

PS C:\Users\lijiaxiang\myfolder> python ex10.py
        I'm tabbed in.
I'm split
on a line.
I'm \ a \ cat.

I'll do a list:
        * Cat food
        * Fishies
        * Catnip
        * Grass

人生就是没有意义的积极向上。 继续学习。

提问11: input()和调查问卷

任何软件处理数据都是 input\(\to\) transform\(\to\) output 。

每行 print 后面加了个逗号 , 了吧?这样的话 print 就不会输出新行符而结束这一行跑到下一行去了。

print("How old are you?",
age = raw_input())
print("How tall are you?",
height = raw_input())
print("How much do you weigh?",
weight = raw_input())

print("So, you're %r old, %r tall and %r heavy." % (age, height, weight))

实际上,我没有看懂raw_input 中间为什么是空的。 英文版我也没太看得懂,所以现在来说,这个问题先过了。

我明白了,其实这个就是个调查问卷的讨论。

f的功能就是替代了.format()了,看下面的例子。

a = "Hello"
b = "World"
print(f"{a} {b}")
print(f"{a + ' ' + b}")

之后看英文版,中文版本有点老了。

PS C:\Users\lijiaxiang\myfolder> python .\ex11.py
How old are you?

一个个的问问题,回答24

PS C:\Users\lijiaxiang\myfolder> python .\ex11.py
How old are you? 24
How tall are you?

接着问,

PS C:\Users\lijiaxiang\myfolder> python .\ex11.py
How old are you? 24
How tall are you? Alex
How much do you weigh?

接着问,

PS C:\Users\lijiaxiang\myfolder> python .\ex11.py
How old are you? 24
How tall are you? Alex
How much do you weigh? 80
So, you're 24 old, Alex tall and 80 heavy.

并且,x = int(input())保证输出是数字,可以进行运算。

用到的书,

习题12:

苹果自带的软件不能复制粘贴书上的文字,太渣了。

Exercise 12. Prompting People

就是说input要给点提示, 如y = input("Name?")

age = input("How old are you? ")
height = input("How tall are you? ")
weight = input("How much do you weigh? ")

这样就不需要单独领出来"How old are you? "来print了。

age = input("How old are you? ")
height = input("How tall are you? ")
weight = input("How much do you weigh? ")

print(f"So, you're {age} old, {height} tall and {weight} heavy."

这里不work,换了这个

# print(f"So, you're {age} old, {height} tall and {weight} heavy.")

print("So , you're %r old, %r tall and %r heavy." %(age, height, weight ))

但是实际上, "How old are you? "也会print出来的。

$ python ex12.py 
How old are you? 24
How tall are you? 185
How much do you weigh? 80
So , you're '24' old, '185' tall and '80' heavy.

Exercise 13. Parameters, Unpacking, Variables

What’s the difference between argv and input()? The difference has to do with where the user is required to give input. If they give your script inputs on the command line, then you use argv. If you want them to input using the keyboard while the script is running, then use input().

这里就解释了两者东西在取舍时的条件。

from sys import argv
# read the WYSS section for how to run this
script, first, second, third = argv

print("The script is called:", script)
print("Your first variable is:", first)
print("Your second variable is:", second)
print("Your third variable is:", third)
$ python ex13.py a b c
The script is called: ex13.py
Your first variable is: a
Your second variable is: b
Your third variable is: c

所以这里a b c可以是不一样的。

Exercise 14. Prompting and Passing

from sys import argv
 
script, user_name = argv
prompt = 'answer: '

print(f"Hi {user_name}, I'm the {script} script.")
print("I'd like to ask you a few questions.")
print(f"Do you like me {user_name}?")
likes = input(prompt)

print(f"Where do you live {user_name}?")
lives = input(prompt)

print("What kind of computer do you have?")
computer = input(prompt)

print(f"""
Alright, so you said {likes} about liking me.
You live in {lives}. Not sure where that is.
And you have a {computer} computer. Nice.
""")
$ python ex14.py jiaxiang
Hi jiaxiang, I'm the ex14.py script.
I'd like to ask you a few questions.
Do you like me jiaxiang?
answer: 1
Where do you live jiaxiang?
answer: 1
What kind of computer do you have?
answer: 1

Alright, so you said 1 about liking me.
You live in 1. Not sure where that is.
And you have a 1 computer. Nice.

思考中间有什么骚操作没有? 我回答了名字、yes、住址、电脑。 但是代码实现的阶段是。 只不过input这里相当于加了个前缀、符号而已,不加只用input()也可以的。

Exercise 15. Reading Files

pydoc open这里pydoc相当于helpopen相当于某个要查询的函数。 这里类似于read_*in R。 实际上, .read()是已经内置的read功能函数。

from sys import argv

script, filename = argv

mytxt = open(filename)

print(f"Here's your file {filename}: ")
print(mytxt.read())

print("Type the filename again: ")
myfile_again = input("> ")

mytxt_again = open(myfile_again)
print(mytxt_again.read())

注意这里第一个input,通过命令完成, python ex15.py ex15_sample.txt。 第二个通过,input()

$ python ex15.py ex15_sample.txt 
Here's your file ex15_sample.txt: 
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
Type the filename again: 
> ex15_sample.txt       
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.

Exercise 16. Reading and Writing Files

好无聊,明天再弄。

You only need to remember that write takes a parameter of a string you want to write to the file.

这个地方开始设计一个程序了。

from sys import argv

script, filename = argv

print(f"We're going to erase {filename}.")
print("If you don't want that, hit CTRL-C (^C).")
print("If you do want that, hit RETURN.")

这个地方的反馈是非常easy的,就是{filename}类似于%r的。

w代表以的方式打开一个文件。 不然这里没办法t.truncate()

input("?")

print("Opening the file...")
target = open(filename, 'w')
line1 = input("line 1: ")
line2 = input("line 2: ")
line3 = input("line 3: ")

print("I'm going to write these to the file.")

target.write(line1)
target.write("\n")
target.write(line2)
target.write("\n")
target.write(line3)
target.write("\n")

print("And finally, we close it.")
target.close()

输出:

PS C:\Users\lijiaxiang\Downloads\trans\myfolder> python .\ex16.py test.txt
We're going to erase test.txt.
If you don't want that, hit CTRL-C (^C).
If you do want that, hit RETURN.
?
Opening the file...
Now I'm going to ask you for three lines.
line 1: 1
line 2: 2
line 3: 3
I'm going to write these to the file.
And finally, we close it.

PS C:\Users\lijiaxiang\Downloads\trans\myfolder> cat .\test.txt
1
2
3

'w' open for writing, truncating the file first 但是实际上不需要.truncate的。 用python -m pydoc open查看。

可以测试这一点。 # target.truncate()掉,看看。

PS C:\Users\lijiaxiang\Downloads\trans\myfolder> python .\ex16.py test.txt
We're going to erase test.txt.
If you don't want that, hit CTRL-C (^C).
If you do want that, hit RETURN.
?
Opening the file...
Truncating the file. Goodbye!
Now I'm going to ask you for three lines.
line 1: 11
line 2: 22
line 3: 33
I'm going to write these to the file.
And finally, we close it.
PS C:\Users\lijiaxiang\Downloads\trans\myfolder> cat .\test.txt
11
22
33

真的是啊,那怎么办?仅仅是修改不行吗?

\(\Box\)不好查。

Exercise 17. Copy Files

书上的代码有问题,做了两处修改。

str(indata),因为wirte的时候,不是str的。 open(from_file,'rb')写的时候,不是utf-8,这里加上'rb' ( python - UnicodeDecodeError: ‘utf8’ codec can’t decode byte 0xa5 in position 0: invalid start byte - Stack Overflow )。

from sys import argv
from os.path import exists # verify the existence of a file.

script, from_file, to_file = argv

print(f"Copying from {from_file} to {to_file}")

# we could do these two on one line, how?
in_file = open(from_file,'rb')
indata = in_file.read()

# open(from_file).read()

print(f"The input file is {len(indata)} bytes long")

print(f"Does the output file exist? {exists(to_file)}")
print("Ready, hit RETURN to continue, CTRL-C to abort.")
input()

out_file = open(to_file, 'w')
out_file.write(str(indata))

print("Alright, all done.")

out_file.close()
in_file.close()
PS C:\Users\lijiaxiang\Downloads\trans\myfolder> echo "This is a test file." > test1.txt
PS C:\Users\lijiaxiang\Downloads\trans\myfolder> cat .\test1.txt
This is a test file.
PS C:\Users\lijiaxiang\Downloads\trans\myfolder> python .\ex17.py .\test1.txt test2.txt
Copying from .\test1.txt to test2.txt
The input file is 46 bytes long
Does the output file exist? True
Ready, hit RETURN to continue, CTRL-C to abort.

Alright, all done.

Exercise 18. Names, Variables, Code, Functions

写function,就是用def

What does the * in *args do? That tells Python to take all the arguments to the function and then put them in args as a list. It’s like argv.

# this one is like your scripts with argv
def print_two(*args):
    arg1, arg2 = args
    print(f"arg1: {arg1}, arg2: {arg2}")

这里别忘了缩进,Python对缩进很敏感。

# ok, that *args is actually pointless, we can just do this
def print_two_again(arg1, arg2):
    print(f"arg1: {arg1}, arg2: {arg2}")

# this just takes one argument
def print_one(arg1):
    print(f"arg1: {arg1}")

# this one takes no arguments
def print_none():
    print("I got nothin'.")

print_two("Zed","Shaw")
print_two_again("Zed","Shaw")
print_one("First!")
print_none()

结果为

IndentationError: expected an indented block
PS C:\Users\lijiaxiang\Downloads\归档\trans\myfolder> python .\ex18.py
arg1: Zed, arg2: Shaw
arg1: Zed, arg2: Shaw
arg1: First!
I got nothin'.

Exercise 19. Functions and Variables

这里f类似于.format()

def cheese_and_crackers(cheese_count, boxes_of_crackers):
    print(f"You have {cheese_count} cheeses!")
    print(f"You have {boxes_of_crackers} boxes of crackers!")
    print("Man that's enough for a party!")
    print("Get a blanket.\n")


print("We can just give the function numbers directly:")
cheese_and_crackers(20, 30)


print("OR, we can use variables from our script:")
amount_of_cheese = 10
amount_of_crackers = 50

cheese_and_crackers(amount_of_cheese, amount_of_crackers)


print("We can even do math inside too:")
cheese_and_crackers(10 + 20, 5 + 6)


print("And we can combine the two, variables and math:")
cheese_and_crackers(amount_of_cheese + 100, amount_of_crackers)

注意def的时候,不要忘记缩进。

> python .\ex19.py
We can just give the function numbers directly:
You have 20 cheeses!
You have 30 boxes of crackers!
Man that's enough for a party!
Get a blanket.

OR, we can use variables from our script:
You have 10 cheeses!
You have 50 boxes of crackers!
Man that's enough for a party!
Get a blanket.

We can even do math inside too:
You have 30 cheeses!
You have 11 boxes of crackers!
Man that's enough for a party!
Get a blanket.

And we can combine the two, variables and math:
You have 110 cheeses!
You have 50 boxes of crackers!
Man that's enough for a party!
Get a blanket.

Exercise 20. Functions and Files

回忆Exercise 13,$ python ex13.py a b c,因此在powershell中跑的时候, 要注意加入各个变量。

from sys import argv

script, input_file = argv # 这里导入想要几个参数

def print_all(f):
    print(f.read()) # 不要忘记缩进

def rewind(f):
    f.seek(0)

def print_a_line(line_count, f):
    print(line_count, f.readline())

current_file = open(input_file)

print("First let's print the whole file:\n")

print_all(current_file)

print("Now let's rewind, kind of like a tape.")

rewind(current_file)

print("Let's print three lines:")

current_line = 1
print_a_line(current_line, current_file)

current_line = current_line + 1
print_a_line(current_line, current_file)

current_line = current_line + 1
print_a_line(current_line, current_file)
> python .\ex20.py .\test.txt
First let's print the whole file:

11
22
33

Now let's rewind, kind of like a tape.
Let's print three lines:
1 11

2 22

3 33

如何理解?

First let's print the whole file:

11
22
33

这是目标文档test.txt的全部三行。 在ex20.py中, 我们定义好 script, input_file = argv # 这里导入想要几个参数 当我们要操作$ python时, script代表了ex20.pyinput_file代表了我们想被执行文档名称test.txt

继续, .seek(0)使得文档从第一行开始录入。 每次.readline()一次,类似于于光标下移到下一个\n之时。

下面的代码框表示,每次数字加1,表示代码框下移1次,然后print出来这一行是个啥。

current_line = current_line + 1
print_a_line(current_line, current_file)

Exercise 21. Functions Can Return Something

def add(a, b):
    print(f"ADDING {a} + {b}")
    return a + b

def subtract(a, b):
    print(f"SUBTRACTING {a} - {b}")
    return a - b

def multiply(a, b):
    print(f"MULTIPLYING {a} * {b}")
    return a * b

def divide(a, b):
    print(f"DIVIDING {a} / {b}")
    return a / b


print("Let's do some math with just functions!")

age = add(30, 5)
height = subtract(78, 4)
weight = multiply(90, 2)
iq = divide(100, 2)

print(f"Age: {age}, Height: {height}, Weight: {weight}, IQ: {iq}")


# A puzzle for the extra credit, type it in anyway.
print("Here is a puzzle.")

就是在def中加入了return这个东西,没什么新的。

> python  .\ex21.py
Let's do some math with just functions!
ADDING 30 + 5
SUBTRACTING 78 - 4
MULTIPLYING 90 * 2
DIVIDING 100 / 2
Age: 35, Height: 74, Weight: 180, IQ: 50.0
Here is a puzzle.

Exercise 23. Strings, Bytes, and Character Encodings

这一节好复杂,算了。我还是好好看看我的Python代码吧。

PS C:\Users\lijiaxiang\Downloads\me\trans\myfolder> python .\ex23.py utf-8 strict
b'Afrikaans' <===> Afrikaans
b'\xe9\x87\x86\xe7\x8a\xaa\xe5\x9e\xb1\xe9\x87\x84\xee\x85\x9a\xe5\xa7\x8f' <===> 釆犪垱釄姏
b'\xe8\xa2\x97\xe5\x92\xac\xe8\xa4\x8b\xe8\xa4\x95\xe8\xa8\x96\xe9\x82\xaa' <===> 袗咬褋褕訖邪
b'\xe4\xb8\x95\xe8\xb3\xb1\xe6\xaf\x93\xe4\xb9\x87\xe4\xba\x98\xe8\xb3\xb7\xe4\xb8\x9e' <===> 丕賱毓乇亘賷丞
b'Aragon\xe8\x8c\x85s' <===> Aragon茅s
b'Arpetan' <===> Arpetan
b'Az\xe8\x93\xb9rbaycanca' <===> Az蓹rbaycanca

We call these 1s and 0s “bits.” At the small end a computer will use 8 of these 1s and 0s to encode 256 numbers (0-255). 00000000 would be 0, 11111111 would be 255 Today we call a “byte” a sequence of 8 bits (1s and 0s). but now we just say it’s 8 bits.

The most popular convention ended up being American Standard Code for Information Interchange or ASCII. This standard maps a number to a letter. The number 90 is Z, which in bits is 1011010, which gets mapped to the ASCII table inside the computer.

所以 ASCII 是这样来的。

print(0b1011010)
# 90

print(ord('Z'))
# 90

print(chr(90))
# Z

这就是字母的编码。

The problem with ASCII is that it only encodes English and maybe a few other similar languages. Remember that a byte can hold 256 numbers (0-255, or 00000000-11111111). Turns out, there’s a lot more characters than 256 used throughout the world’s languages.

这也说明了为什么ASCII为什么不适用于中文了。

p.109


需要用到的软件和书在这。