0% found this document useful (0 votes)
32 views73 pages

Python Class

Uploaded by

8jxbgbdcxs
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views73 pages

Python Class

Uploaded by

8jxbgbdcxs
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 73

Python

TEL: (+1) 917-302-6640, (+1) 929-300-2772


TEL: (+1) 917-302-6640, (+1) 929-300-2772 | Email: [email protected] | WeChat ID: BiAnTongZhou
WeChat ID: BiAnTongZhou | Website: www.beyondjoy.us
Website: www.itnyc.tech | Address: 136-31 41st Ave #2A, Flushing, NY 11355 0
目录

LESSON 1. PYTHON INSTALL AND JUPYTER NOTEBOOK...............................................2

LESSON 2. NUMBERS,STRINGS AND FORMATTED OUTPUT...........................................7

LESSON 3. LISTS,SETS,DICTIONARIES AND TUPLES...................................................25

LESSON 4. BOOLEAN、逻辑表达、IF 条件语句............................................................................37

LESSON 5. 循环变量和循环语句、FOR LOOP...............................................................................43

LESSON 6. 当型循环 – WHILE LOOP.................................................................................47

LESSON 7. 函数 FUNCTION, BUILT-IN FUNCTIONS 与迭代 RECURSION...................................49

LESSON 8. 模块 – 以 DATETIME,PANDAS,NUMPY 为例.........................................................61

LESSON 9. 正则表达式 REGULAR EXPRESSION...................................................................75

LESSON 10. ERROR AND EXCEPTION HANDLING.......................................................85

LESSON 11. 函数的高级特性............................................................................................... 89

LESSON 12. 面向对象程序设计初步..........................................................................................96

Beyond Joy Education – Confidential – Internal Distribution


1
PYTHON 实战课程

LESSON 1. PYTHON INSTALL AND JUPYTER NOTEBOOK


前言: PYTHON
A. 实用与流行
1) Python 是非常流行的程序语言,很多大型网站都是用 Python 开发的,比如 YouTube,Instagram
等等;
2) 数据分析方面 Python 的普及性遥遥领先其他语言;

Beyond Joy Education – Confidential – Internal Distribution


2
上三图全部来自 kaggle - Novice to Grandmaster- What Data Scientists say?

Python 的不可替代性更强,是一种必要的数据分析语言。
在资深数据分析人员的推荐当中,Python 也远胜另一种流行的语言 R。
那么学 python,用什么平台,怎么学,我们也要有针对性,下面这张图足以说明一切。可以看出,大部分 data 从业者都很常用
jupyter notebook 和 SQL,这也是我们这门课的平台和重点。

Beyond Joy Education – Confidential – Internal Distribution


3
3) 大量的第三方 module,可以直接用来使用;
常用的 numpy, scipy, matplotlib, scikit learn,等等,以及 python 自带的标准库,能够大量而且高效地分析
和处理各类数据,尤其正则表达式可以高效处理字符串。
B. Install Anaconda
C. Run Jupyter Notebook
D. Input and Output
i. Play with the interactive notebook
什么是 cell?
快捷键
 Esc 进入命令模式后,方向键可以进行导览
 在命令模式中,可以进行如下快捷键操作:
o A 在现有 cell 上方添加新 cell, B 在下方添加新 cell
o shift + enter run 现 cell 并向下选择
o ctrl + enter run 现 cell
o c copy 现在的 cell
o V paste 现在的 cell
o I + I interrupt kernel

Beyond Joy Education – Confidential – Internal Distribution


4
o 0 + 0 restart kernel
o M 将现有的 cell 变成 markdown cell
o Y 将现有的 cell 变成 code cell
o D + D 删除现有 cell
o H 查看所有快捷键
 Enter 退出命令模式,返回当前 cell 进行编辑
 Tab 缩进或提示代码
 Ctrl + /将所选的所有代码转换为注释/转换回代码
 Ctrl + S 保存代码

查看当前工作的目录,更改当前工作的目录
查看当前工作目录 pwd
更改工作目录 cd + 新工作目录
返回上一级 cd ..

ii. 基本语法
在学习 Python 课程之前,我们先来看看这门语言自身的基本语法

注释
Python 中的单行注释以#开头
多行注释用三个引号标注开头和结尾

缩进
Python 中并没有分行符号 ; 等,每一行代码之间使用缩进来区分,每一个 block of code 必须缩进相同的空格数
一般而言,我们使用制表符 tab 来进行缩进,每一级的代码之间缩进一个 tab 或四个空格,二者等价。

数据类型

python 中数有三种类型:整数、浮点数和复数。
整数, 如 1, 2, 3 等不带小数点的数字,在 python3 中,int 具有 unlimited size 的特性,因此不再有 long 长整
数类型
浮点数 如 1.23、2E10 等
复数 如 1 + 2j、 1.1 + 2.2j

iii. Simple input and output

尝试让 python 从键盘接受一个字符串

>>> name = input('Please enter your name ')


>>>print('Your name is',name)

Beyond Joy Education – Confidential – Internal Distribution


5
尝试输出:
>>>print('hello, world')
输出多个字符串时,使用逗号隔开,python 会自动添加空格并输出
>>> print('Good morning!','How are you doing today?')
Good morning! How are you doing today?
print 当中也可以直接添加数字或者计算公式
>>>print(15*4)
60
或者可以混合字符串和数学公式
>>>print('15 * 4 = ',15*4)
15 * 4 = 60

LESSON 2. NUMBERS,STRINGS AND FORMATTED OUTPUT


首先我们尝试在 notebook 中进行以下操作
>>>2
2
>>>3.5
3.5
>>>2.0
2.0
刚才我们已经看到了 Python 的两种数字类型,整型和浮点型。

Python 中的变量格式与数字基础

格式名 类型 说明
Integers int 整数,如 1,2,3,40
Floating
float 浮点数,如 1.2,2.3,5.0
point
Strings str 有序的,一系列单个字符的合集,如"hello world"
Boolean bool 逻辑变量,包含 True 和 False
Lists list 有序的对象列表,如[10,'hello',12.3]
无序的,关键字+对应值 配对组成的合集,如
Dictionaries dict
{"Kevin":10,"Kevin":15}
Tuples tup 有序的不可变的对象列表,如(10,'hello',12.3)
Sets set 无序的,不重复的变量列表{"a","b","c"}

A. 两种数字格式 integer, float


i. 整数的初始化和计算
Python 中的整数型为 int,使用时无需声明,内置函数 int()可以将 string,float 类型的数字转化为整数,注意 float 类型
转化为整型时,小数点后直接 drop。整数运算时,整数可能被自动转化为浮点数。

Beyond Joy Education – Confidential – Internal Distribution


6
例 1. 将 string 转化为整数 int()
a = '14'
b=2
print(a+b) #Error – 不能将字符型和整型直接相加
print(int(a)+b) #Output 16
ii. 浮点数的初始化和计算
1) Python 中的浮点数类型为 float,使用时无需声明,通过定义时是否含有小数点来区分浮点型,举例 myfloat = 1.0
即定义了一个名为 myfloat 的浮点数,计算时,浮点数的计算返回值一般仍为浮点数。

例 2.
a = 5.75
type(a)
<class 'float'>
2) 浮点数是一种近似。需要格外注意的是,与整型不同,浮点型的数在储存的时候并不是精确的,只是一种对实数的近似。

例 3.
x = 3.1415926
y = 3.1415925 + 0.0000001
print(x == y) #此处的==是判断是否相等的符号,之后我们会详细讲到
#Output False
看到上述例子,我们可以发现,根据自己的直观感受和计算,这两个数字应该是完全相等的,但是计算机却返回了 False,下面我们
尝试 print 出 x 和 y 就可以看出端倪。

例 4.
print(y)
3.1415925999999996
print(x)
3.1415926
我们来尝试打印出来 x 后面隐藏的位数
print('{:.10f}'.format(x)) #这种结构化 string 的输出方式我们之后会讲到,在这里我们只需要知道,小数点后
面的 10 是指 10 位小数,f 是指 floating number 即可
3.1415926000
可以发现 x 与 y 的差异是极小的,但就是这样极小的差异,计算机并不能认为二者相等。所以我们在判断两个浮点数是否相等的时候,
通常只需要判断二者是否足够接近。比如可以这样:
print(x-y<1e-10)
True
就可以达到我们想要的效果了。
3) 科学计数法表示
很多同学可能已经注意到了,上面我们判断 x-y 是否足够小的时候,用到了科学计数法。我们再来看几个例子

例 5.
trillion = 1e12
c = 3e8

Beyond Joy Education – Confidential – Internal Distribution


7
print('The Market Cap of Apple is',trillion,'US dollars')
print('The speed of light traveling is',c)
4) 浮点数转化为整数
我们刚才在整数部分已经学习了一种将浮点数转化为整数的方法 int(),除此之外,还有几种常用的近似方法。

例 6.
round(3.1415)
3
round(3.1415,2)
3.14
Round 还有一个很有趣的用法,就是后面的 round 位数可以为负值,那么为负值的时候是什么含义呢?

例 7.
x = 2018.1234
print(round(x,2))
2018.12
print(round(x,0))
2018.0
print(round(x,-1))
2020.0
print(round(x,-2))
2000.0
可以看出,当后面的精确位为负值的时候,round 会继续向左进行 round 运算,按照 0 是精确到个位,-1 是精确到十
位,-2 是精确到百位,以此类推。
round 同样可以作用于整数。作用于整数的时候返回值也是整数。同学们可以自己探索。
浮点型的转换与整型类似,只是改成 float()即可
iii. type()函数查看变量类型
通过 python 内置函数 type()可以返回变量的类型。
a=5
b = 3.0
c = True
d = 'Mango'

print(type(a))
print(type(b))
print(type(c))
print(type(d))

#Output
<class 'int'>
<class 'float'>
<class 'bool'>
<class 'str'>

Beyond Joy Education – Confidential – Internal Distribution


8
a = (5,6)
b = [3,4,5]
c = set([2,3])
d = {'Mango':8}

print(type(a))
print(type(b))
print(type(c))
print(type(d))

#Output
<class 'tuple'>
<class 'list'>
<class 'set'>
<class 'dict'>
学习了两种数值类型之后,我们还需要注意以下几点:
1) Python 对于整数没有大小限制,而某些语言的整数根据其存储长度是有大小限制的。
2) Python 的浮点数也没有大小限制,但是超出一定范围就直接表示为 inf(无限大)。
B. 数学计算
i. +、-、*、/、**、%、//等基本运算
简单的数学计算,加减乘除,其中,+、-、*运算并不改变返回值类型
整数,浮点数以及计算
Python 可以作为简单计算器使用
加减乘除:5-2, 3*4,6/2 = 3.0,3/2 = 1.5 除法运算会自动将整数转化成浮点数
整数与浮点数的加减乘除运算,自动转化为浮点数,10*0.5 = 5.0, 2+1.0 = 3.0
取余 % : 5 / 4 = 1.25, 5 % 4 = 1,21 % 2 = 1,20 % 2 = 0 常用来辨别奇偶性。
乘方 :2 ** 3 = 8, 3 ** 2 = 9 可以使用 pow(x,n) 计算 x^n
整数除法: 13 // 2 = 6, 8 // 3 = 2

Test 1:What is the result of 1/2 in python? A. 0 B. 0.5 C.1

C. 变量的赋值
目的:方便于在代码中调用。
命名规则:
1) Cannot start with a number – 不能以数字开头
2) NO SPACES in the number, use _ - 变量中不能有空格,可以使用下划线_代替
3) No symbols in :”,<>/?|\()!@#$%^&*~-+ - 不能使用某些特殊字符
4) lower case preferred – 最好小写(通用标准)
5) Do not use words that might cause confusion, such as “list”,”str” – 不能使
用有特定含义的词

Beyond Joy Education – Confidential – Internal Distribution


9
符合要求的变量名举例:
x
x2
TOTAL
even_num
不可以使用作为变量名的 Python keyword
and del from None try
TRU
as elif global nonlocal
E
whil
assert else if not
e
break except import or with
class FALSE in pass yield
continue finally is raise
def for lambda return

Test 2: Test: 以下的变量名,符合命名规则?


Sub-total
_price
4you
class
final result
Else
6) Python 中的变量赋值是支持动态赋值( Dynamic Typing)的 – 即可以将变量重新赋值成不同的
datatype,相比 C++等语言,更加灵活

例 8.
my_age = 26
my_age = “twenty_six” #my_age 变量被 reassigned as string.

注意!This might cause bugs for unexpected data types, so use type()
to identify the data type.

D. str 类型的介绍与应用
i. 通过单引号或者双引号进行声明和赋值, Either single quotes or double quotes is allowed.
ii. 当我们需要在 str 中包含引号而不希望造成计算机编译的混淆时,将单双引号复合使用,即可得到想要的语句

例 9.
'I'm fine, thank you, and you?' #Error - Python is confused
"I'm fine, thank you, and you?" #Good – 单双引号混合使用
那么如果一个字符串中同时含有单双引号需要输出怎么办呢?
需要使用转义符 \
print('I\'ve bought two stocks, \"GOOG" and \"AMZN"')

Beyond Joy Education – Confidential – Internal Distribution


10
I've bought two stocks, "GOOG" and "AMZN".
转义字符\可以转义很多字符,比如\n 表示换行,\t 表示制表符,字符\本身也要转义,所以\\表示的字符就是\
但是当我们的字符串中有大量需要转义的字符时,加入过多的\会造成程序较为复杂,降低可读性,因此 python 推荐使用 raw
strings, 即 r''. 在小写字母 r 后面的字符串,里面的字符将不被转义。
>>>print('\\\t\n\\')
\
\
#此句话打印一个反斜杠,一个制表符,一个换行符和另一个反斜杠,字符全部进行了转义
>>>print(r'\\\t\n\\')
\\\t\n\\
#使用了 raw string 输出,所有字符保持输入状态输出,不进行转义
iii. 不可变性 – 不能改变已经存在的 string 中某一部分,即不可以 assign

例 10.
Immutability of string
my_name = 'Alan'
my_name[1] = 'y' # TypeError - 'str' object does not support item
assignment
iv. 可加性: + 的使用

例 11.
location = 'Times Square'
str1 = 'Here is ' + location
print(str1)
v. 可重复性 - *的使用

例 12.
line_separator = '-'*100
print(line_separator)
vi. 有序性 – 可以使用 index 进行调用,String is a sequence of characters, so we can
use index [] to refer。
str 与 list 类似,通过 index 来指向其中的每一个字符。

例 13.
“Kevin” - index as below
M i l e s
0 1 2 3 4
my_string = ‘Hello world’
vii. str()的使用
与 int(), float()类似,字符串型也可以用内置函数进行类型转换
有趣的是,str()可以处理 None 输入参数。并转换为字符串'None',这一特点是 int()和 float()所不具备的。

Beyond Joy Education – Confidential – Internal Distribution


11
例 14.
>>>str(1)
'1'
>>>str(None)
'None'
viii. [] 的使用,[start:stop:step],从末尾进行调用,倒叙等
1) Try my_string[0], my_string[5], my_string[6]
2) Reverse index, my_string[-1] = ‘d’, my_string[-2] = ‘l’
3) Slice the string my_string[6:], my_string[:10], my_string[6:11],注意在使用 up
to 的时候,右边边界并不包含在内
4) Steps: my_string = “a1b2c3d4e5f6”, my_string[::2] –
string[start:end:step]\

Test 3:
1) Return the ‘J’ in mystring = ‘Beyond Joy’ – mystring[7]
2) Return the ‘Joy’ in mystring = ‘Beyond Joy’ - mystring[7:]
3) Return the ‘cat’ in mystring = ‘Education’ - mystring[3:6]
ix. str 类型的内置函数 methods
1) str.upper(), str.lower()
将 str 中所有的字母转化为大(小)写,其他字符不受影响
在实际使用中,可以将不确定大小写的输入值转化为全部大/小写来进行判断

例 15.
if the user type in Y or y, then print “Yes!”
if input().upper() == 'Y':
print('Yes!')
2) str.isupper(),str.islower()
判断 str 中的字母是否全部为大/小写,如果判断为真则返回 True,反之 False
3) str.join(iterable) 此处 str 类型作为类似分隔符存在,如:
list = ['How', 'are', 'you', 'doing', 'today']
sep = ' '
sep.join(list)
4) str.split(sep=None, maxsplit=-1)
输入变量中的 sep 为分隔符,maxsplit 为最多进行的 split 次数,如果不声明 maxsplit,则默认值为-1,即进行最彻底
的分割

例 16.
>>>class_time = '15:30:00'
>>>class_time.split(sep = ':')
['15', '30', '00']
>>>class_time = '15:30:00'
>>>class_time.split(sep = ':',maxsplit = 1) #最多进行 1 次分割

Beyond Joy Education – Confidential – Internal Distribution


12
['15', '30:00'] #此时返回的 list 中一定含有 maxsplit+1 个元素
5) str.count(substring, start,end)
返回从 start 位置开始到 end 位置结束(不含 end 位置本身)的 substring 的计数,如果不声明 start 与 end,则
遍历整个 string

例 17.
str1 = 'Here is 3 Times Square'
str1.count('s')
str1.count('s',0,8)
6) str.find(substring,start,end)
返回从 start 位置开始到 end 位置结束(不含 end 位置本身)的第一个 substring 的 index,如果不声明 start 与
end,则遍历整个 string

例 18.
str1 = 'Here is 3 Times Square'
str1.find('i')

7) str.partition(sep)
将 str 从第一次出现 sep 字符处进行分割,返回一个 3-tuple,含有 1. sep 前面的部分 2. sep 本身 3. sep 后面的
部分。如果没有找到 sep,则返回同样的 3-tuple,含 str 本身和两个空字符

例 19.
>>>str1 = 'Here is 3 Times Square'
>>>str1.partition('3')
('Here is ', '3', ' Times Square')
>>>str1 = 'Here is 3 Times Square'
>>>str1.partition('%')
('Here is 3 Times Square', '', '')

8) str.startswith(prefix,start,end), str.endswith(suffix,start,end)
顾名思义,即判断 str 是否以某一值开头/结尾。可以通过 start 和 end 来指定判断的位置,如果不指定则判断整个 str

E. 输入和输出
讲完了两种基本的数字类型和 string 字符串类型,我们先不继续讲下面的数据类型,先讲一下 python 的输入和输出。
i. 用户输入 input()
在 python 中,用户的输入可以通过自带的函数 input()来读取并将输入值赋给一个变量。格式通常如下:
x = input()
我们尝试如下代码:
print('Please enter your name: ')
name = input()
print('Hello',name)

Beyond Joy Education – Confidential – Internal Distribution


13
首先,计算机输出一行字向用户请求输入一个名字,然后在第二行 input()执行的时候,程序停止,等待用户输入并键入回车,当用户键
入回车之后,输入值会被赋给 name 变量,下一步打印出来
input()函数本身可以有一行字符串作为输入变量,上述代码可以更加简洁如下:
name = input("Please enter your name: ")
print('Hello',name)
很多时候我们希望将用户输入的数字进行一番计算,这时我们就可以组合使用之前学过的函数和 input()了,比如:
x = input('Please enter an integer: ')
y = input('Please enter another integer: ')
num1 = int(x)
num2 = int(y)
print(num1,'+',num2,'=',num1+num2)
那么,上述代码还能不能够更加简洁呢?答案是可以,我们可以函数套函数,只要记住在最内层的函数最先执行就可以了。
num1 = int(input('Please enter an integer: '))
num2 = int(input('Please enter another integer: '))
print(num1,'+',num2,'=',num1+num2)

课堂练习:写一行代码,向用户请求输入一个数字,无论用户输入的是整数还是浮点数,程序都输出该数字的整数部分。
print(int(float(input('please enter a number: '))))
ii. Print 的使用, formatted string
在这一章节之前我们其实已经无数次用到了 print 函数,也了解了他的一些基本用法,这节课我们再讲一些对 print 的应用。
1) 结束符
print('A')
print('B')
print('C')
A
B
C
上述几行代码,如果我们希望将 A,B,C 打印在同一行中怎么办呢?其实,我们平时在写 print 函数的时候,是省略了结束符的,下面
这两行代码其实是等价的。前者是后者的缩写
print('A',end ='\n' ) #其中\n 就是换行符号
所以只要在使用时显式声明 end 结束符的值就可以了。
print('A',end = ' ')
print('B',end = ' ')
print('C',end = ' ')
ABC
分隔符
x ,y, z = 1, 2, 3
print(x,y,z)
print(x,y,z,sep = ' , ')
print(x,y,z,sep = '$')
iii. formatted string
可以直接输出数字,字符,数字的计算结果等。

Beyond Joy Education – Confidential – Internal Distribution


14
iv. 占位符的使用和举例
在 Python 中,采用的格式化方式和 C 语言是一致的,用%实现,举例如下:
>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hello, %s, you have %d classes today.' % ('Kevin', 2)
'Hello, Kevin, you have 2 classes today.'
从上述代码中可以看出,%运算符就是用来格式化字符串的。在字符串内部,%s 表示用字符串替换,%d 表示用整数替换,有几个占位
符,后面就跟几个变量或者值,顺序要对应好。仅有一个占位符的情况下,可以省略括号。
常见的占位符有:
%d 整数
%f 浮点数
%s字符串
%x 十六进制整数
其中,格式化整数和浮点数还可以指定是否补 0 和整数与小数的位数:
>>> '%2d-%02d' % (3, 1)
' 3-01'
>>> '%.2f' % 3.1415926
'3.14'
如果你不太确定应该用什么,%s 永远起作用,它会把任何数据类型转换为字符串:
>>> 'Age: %s. Gender: %s' % (25, True)
'Age: 25. Gender: True'
有些时候,字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%:
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'

v. {}.format
f'' f-string
>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}" # nested fields
'result: 12.35'
在 python3 中,format printing 改成了{}与.format 配合使用的方式。例如
>>> print('In this course, we will learn {0} and
{1}'.format('Python','SQL'))
In this course, we will learn Python and SQL
>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
>>> '{}, {}, {}'.format('a', 'b', 'c') # 3.1+ only

Beyond Joy Education – Confidential – Internal Distribution


15
'a, b, c'
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
>>> '{2}, {1}, {0}'.format(*'abc') # unpacking argument sequence
'c, b, a'
>>> '{0}{1}{0}'.format('abra', 'cad') # arguments' indices can be
repeated
'abracadabra'
还可以直接引用 list 内部的变量
>>> coord = (3, 5)
>>> 'X: {0[0]}; Y: {0[1]}'.format(coord)
'X: 3; Y: 5'
通用计数法
>>> '{:,}'.format(1234567890)
'1,234,567,890'
百分数表示
>>> points = 2
>>> total = 3
>>> '2/3 is {:.2%}'.format(points/total)
'2/3 is 66.67%'
在 format 中直接定义并调用变量名
>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N',
longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'
使用关键字输出字典型变量
>>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
>>> 'Coordinates: {latitude}, {longitude}'.format(**coord)
'Coordinates: 37.24N, -115.81W'
format 内的数值或字符可以反复调用,如:
print(“The Penn Station is between {0} st. and {1} st. and the Empire
State Building is at {1} st.”.format(32,34))
更复杂的用法, 设置浮点数的输出格式
>>>'The {0} growth rate is {1:.2f}% as of 2017.'.format('GDP',7.5)
vi. 使用 curly braces 设定 width 和其他格式
更复杂的用法,在{}中设置输出宽度
for i in range(1,12):
print("The {0:2} square is {1:4} and cube is {2:4}".format(i,i**2,i**3))
vii. {value:width.precision f}模式使用和举例(new)
更复杂的用法, 设置浮点数的输出格式
Print(“The result of 2/3 is approximately {0:12.50}”.format(2/3))
viii. 最新的 f””模式(new at Python 3.6),使用!r 输出引号

Beyond Joy Education – Confidential – Internal Distribution


16
扩展: https://docs.python.org/3/library/string.html#formatstringss

F. I/O files 基本操作


本节课的最后,我们再来讲一下 python 中文件的 I/O。
Files 也是 python 数据类型的一种,顾名思义,就是我们平时在电脑上可以打开,读写的文件,其中,最基础也最常用的一种就
是.txt 文件。Python 的基础库中,对于.txt 文件有着完整而强大的支持,下面我们来学习一下。

i. 新建或打开一个文件
我们先来新建一个文本文件
f = open('my_file.txt')
程序报错了,因为我们并没有这样一个 file 存在,在没有同名文件存在的情况下,
我们通过添加一个参数来告诉 Python 新建一个文件
f = open('my_file.txt','w')
'w'这个参数是用来声明,我们需要写入权限,此时 python 就会新建一个 my_file
文件并开始准备写入内容。
很多时候,我们也需要打开一个已有的文件,此时就会面对一个文件路径的问题,在
不同的操作系统中,路径的写法有一些细微的不同。
Windows 系统:
'C:\\Users\\Kevin\\Desktop'
双斜杠的作用是为了让系统不对反斜杠进行转义。
Mac 系统
'/Users/Kevin/Desktop'
由于 Mac 系统中的路径上下级通过/表示,故不需要转义符操作。
下面,尝试在自己的桌面或者自己喜欢的文件夹中,创建一个新的 my_file.txt 文件。

ii. 写入
新建了 txt 文件之后,我们来看一下写入操作。
f = open('my_file.txt','w')
f.write('An old silent pond...\n')
f.write('A frog jumps into the pond,\n')
f.write('splash! Silence again.\n')
f.close()
打开文件查看结果。

iii. 读取

有几种不同的读取方式

Beyond Joy Education – Confidential – Internal Distribution


17
(1) f.read()方式,读取文件中所有内容
f = open('my_file.txt','r')
f.read()
(2) f.readline()读取文件中的单行
f = open('my_file.txt','r')
f.readline()

(3) f.readlines()读取每一个单行并返回一个含有所有行的 list


f = open('my_file.txt','r')
f.readlines()
除了最常见的'w', 'r', 还有'w+', 'r+', 'wb+', 'rb+'等等

iv. 其他操作
(1) 通常我们打开文件之后要进行多项操作,此时使用 with 命令,可以在命令结尾自动关闭文件,并会忽略读写过程中的异常。

with open('my_file.txt') as f:
read_data = f.read()
(2) f.seek(offset[,whence])
f.read()操作会操作光标进行后移,如果我们需要将光标移动到想要的位置,
fo = open("my_file.txt", "r+")

line = fo.readline()
print(line)

line = fo.readline()
print(line)

#set the pointer to the beginning


fo.seek(0, 0)
line = fo.readline()
print (line)
# Close opend file
fo.close()

(3)open the file as append mode,在文件末尾写入新内容


with open('my_file.txt','a') as f:
f.write('We are writing a new line here\n')
练习 1:写代码将 my_file 打开并读出我们刚刚添加的这一句话
练习 2:写一个自己的 text 文件,其中内容包含 I love Python!一句话

Beyond Joy Education – Confidential – Internal Distribution


18
LESSON 3. LISTS,SETS,DICTIONARIES AND TUPLES
A. list 类型
i. [12,”abc”,30.95] 储存不同的数据格式,有序,逗号分隔,[]创建
list1 = [12,'good',5.0]
list2 = [1,2,3,4,5]
以上均可接受
或者可以将其他的 collection 类型转化 list,与 int(),float(),str()类似
my_tuple = (1,2,3)
my_list = list(my_tuple)

>>>print(my_list)
[1,2,3]
ii. 可以使用 index 调用,与 string 类似,注意 index 从 0 开始
list = [8,9,10]

>>>list[0]
8
iii. 切片特性
这一特性适用于 list 和 tuple,string 三种数据类型。
假设我们的 portfolio 中有各种不同的股票
Holdings = ['GOOG','FB','NVDA','TSLA','HD']
我们已经知道通过 index 可以取出其中任何一个位置的元素。那么如果我们想要取出不止一个元素呢?如何一次性取出前三个股票名呢?
自然可以使用穷举法
[Holdings[0],Holdings[1],Holdings[2]]
['GOOG', 'FB', 'NVDA']
或者我们也可以使用循环,每次取出一个元素,组合在一起。但是我们这节课先不涉及循环,而是学习一下 Python 中独特的 slice
特性,中文可以译作切片操作。
Holdings[0:3] #表示从 0 开始,取到 3 为止,但是不包括 3,数学上可写成[0,3)
['GOOG', 'FB', 'NVDA']
联想到 list 可以通过 index = -1 取到最后一位,可以想到 python 也支持从倒数位置开始 slice Holdings
Holdings[-2:-1]
['TSLA']
当 list 中的元素非常多的时候,slice 操作格外有实用价值。
new_list = list(range(100))
new_list[0:20]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
默认情况下,slice 的开头是 index = 0,结尾是最后一个元素,因此我们也可以省略一些输入变量
new_list[:20]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
new_list[90:]
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

Beyond Joy Education – Confidential – Internal Distribution


19
slice 操作同样提供了 step 特性,即设置步长,如果我们想要 20 以内的偶数
new_list[:20:2]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
看了这么多例子,我们可以总结出 slice 操作的基本格式 list[start:end:step]
iv. 可变性,可以直接改变 List 中的元素
list = [1,2,3,4]

>>>list[0] = 5
>>>print(list)
[5,2,3,4]
v. list.append(), list.extend().list.pop(index)与.remove(obj)
list 的加减成员,可以通过几个不同的函数来实现,下面我们看一下 append()
顾名思义,append 即为在 list 的末尾添加上新的成员,这一成员并不一定需要跟前面的成员为相同类型,只需要在
append()括号内加入想要添加的成员即可。但是要注意的是,append()是直接作用于 list 本身的函数,并不返回任何值,但
list 本身会直接被改变。

例 20.
even_list = []
for i in range(15):
if i % 2 == 0:
even_list.append(i)

>>>print(even_list)
[0, 2, 4, 6, 8, 10, 12, 14]

例 21.
如果我们有两个 list,想要把两个 list 合成一个呢?
list1 = [1,2,3]
list2 = [4,5,6]

>>>list1.append(list2)
>>>print(list1)
[1, 2, 3, [4, 5, 6]]
可以看出,list2 是作为一个整体被添加到了 list1 的最后,这不是我们想要的结果,那我们如果想要把 list2“打开”然后添加进
list1,能怎样操作呢?
list1 = [1,2,3]
list2 = [4,5,6]

>>>list1.extend(list2)
>>>print(list1)
[1, 2, 3, 4, 5, 6]

Beyond Joy Education – Confidential – Internal Distribution


20
可以看出,extend 函数实现了这一功能。同样要注意的是,extend 也是 inplace 的,并不返回任何值但是直接作用于
list 本身。
那么如果我们想要删除 list 中的一个值呢,首先,由于 list 可以通过 index 来引用,我们自然而然会想到,删除掉某一 index
上的值
list.pop(index)
list1 = [1,2,3,4,5,6]

>>>list1.pop(5)
6
>>>print(list1)
[1,2,3,4,5]
值得注意的是,list1.pop(5)函数执行时,不仅删除掉了位于 index = 5 位置上的数字,还返回了这一数字。这一特性在今
后 list 的应用中会很有用处。
如果我们对 list 的内容有所了解,想要直接删除某个值而不是通过 index 来引用,就需要用到 remove(), remove()也
是没有返回值,直接作用于 list 本身的
list1.remove(1)

>>>print(list1)
[2,3,4,5]
注意,如果 list 中有两个相同的值,那么 remove 只会删除第一次出现的那个。
vi. List.sort() – inplace 函数,返回 None, optional - reverse = TRUE 反向排列
对于一列存储于 list 当中的数或者字符串,我们经常需要对其进行排列。python 的 list 提供了这一功能。但是注意,sort 函数
也是没有返回值的函数,经常有人误以为 sort()可以返回一个排好序的序列,而使用了错误的写法。
mylist = [3,6,1,4,9,2,8,13]
sorted_list = mylist.sort() #错误,该函数返回值是 None

>>>print(sorted_list)
None

mylist.sort()

>>>print(mylist)
[1, 2, 3, 4, 6, 8, 9, 13]

mylist.sort(reverse=True)

>>>print(mylist)
[13, 9, 8, 6, 4, 3, 2, 1]
为了实现排序的同时赋值,我们可以用另一个自带函数 sorted()
sorted_list = sorted(mylist)

>>>print(sorted_list)

Beyond Joy Education – Confidential – Internal Distribution


21
[1, 2, 3, 4, 6, 8, 9, 13]
vii. list.reverse()
将 list 中的元素倒过来
mylist = [3,6,1,4,9,2,8,13]
mylist.reverse()

>>>print(mylist)
[13, 8, 2, 9, 4, 1, 6, 3]
viii. list.count()
对 list 中的成员进行计数
list1 = [123, 'xyz', 'ddd', 'abc', 123]

>>>print('count for 123: ', list1.count(123))


>>>print('count for abc: ', list1.count('abc'))
count for 123: 2
count for abc: 1
ix. list.copy()
返回 list 的一个复制品,为什么我们不能直接将 list 赋值给一个新的 list 而是要进行 copy 呢?
list1 = [123, 'xyz', 'ddd', 'abc', 123]
list2 = list1
list2.pop(0)

>>>print(list2)
>>>print(list1)
['xyz', 'ddd', 'abc', 123]
['xyz', 'ddd', 'abc', 123]
可以看出,在我们改变 list2 的同时,list1 也被改变了,而这种改变通常是我们不想要的。因此我们在给 list2 定义和赋值的时候,
应该使用 list1.copy()
list1 = [123, 'xyz', 'ddd', 'abc', 123]
list2 = list1.copy()
list2.pop(0)

>>>print(list2)
>>>print(list1)
['xyz', 'ddd', 'abc', 123]
[123,'xyz', 'ddd', 'abc', 123]
list 还有一些其他的函数,我们不需要一一介绍,在日后使用的过程中逐渐学习即可。附上 list 的函数表。

Method 描述
list append() 添加一个元素
list extend() 将另一个 list 中的元素添加进来

Beyond Joy Education – Confidential – Internal Distribution


22
list insert() 在 list 中插入元素
list remove() 从 list 中 remove 某个元素
list index() 返回某个值第一次出现的 index
list count() 对某个值的出现次数进行计数
list pop() 根据给定的 index 删除元素并返回该值
list reverse() 倒转一个 list
list sort() 排序,默认为升序,可以通过 reverse = True 来降序排列
list copy() 返回 list 的一个 copy
list clear() 将 list 中的所有成员清空
B. Dictionaries
i. Unordered mapping for storing objects{“key1”:value1, “key2”:value2}
顾名思义,字典类型就是包含了关键字以及关键字对应的值得一种储存方式。其中的关键字是用来索引的关键值,因此 key 不可重复,不
可更改。
其次要注意,dict 内部存放的顺序与放入 key 的顺序无关。
与 list 相比,dict 有两个主要特点:
1) 优点:查找和插入的速度快,因为是无序储存,不会因为内部数据量增加而减慢查找速度
2) 缺点:内存占用量很大
ii. 初始化,赋值,调用(分为直接调用,.values(), .items()等函数调用)
创建一个字典
my_dict = {'key1':'value1','key2':'value2'}
or
my_dict = dict(key1='value1',key2='value2')
使用关键字提取字典中的值
my_dict['key2']
'value2'
my_dict.get('key2')
'value2'
字典所包含的变量是非常灵活多样的,可以是 string, integer 甚至是 List
y_dict = {'key1':111,'key2':[11,22,33],'key3':['value1','value2','value3']}
>>>my_dict['key2']
[11,22,33]
由于返回的是一个 List,我们可以叠加[]来调用里面的数值
>>>my_dict['key2'][0]
11
字典中的数值可以变动
>>>my_dict['key1'] = my_dict['key1'] *0
>>>my_dict['key1']
0
除了在字典建立的时候进行赋值,我们同样可以创建一个空字典然后往里面添加值
my_dict = dict()
my_dict['class'] = 'Python'

Beyond Joy Education – Confidential – Internal Distribution


23
my_dict['teacher'] = 'Kevin'
>>>print(my_dict)
{'class': 'Python', 'teacher': 'Kevin'}
我们今天再介绍几种 dict 的方法
dict.keys()
d = {'key1':1,'key2':2,'key3':3}
返回字典的所有关键字
>>>print(d.keys())
dict_keys(['key1', 'key2', 'key3'])
返回字典所包含的所有值
>>>print(d.values())
dict_values([1, 2, 3])
返回以 tuple 形式存在的关键字与对应值的成对组合
>>>print(d.items())
dict_items([('key1', 1), ('key2', 2), ('key3', 3)])
Dictionary
Methods
Method Description
clear() Removes all the elements from the dictionary
copy() Returns a copy of the dictionary
fromkeys() Returns a dictionary with the specified keys and values
get() Returns the value of the specified key
items() Returns a list containing the a tuple for each key value pair
keys() Returns a list contianing the dictionary's keys
pop() Removes the element with the specified key
popitem() Removes the last inserted key-value pair
setdefault( Returns the value of the specified key. If the key does not
) exist: insert the key, with the specified value
update() Updates the dictionary with the specified key-value pairs
values() Returns a list of all the values in the dictionary

C. Tuples
i. Tuple 是非常类似 list 的,但是具有不可变性的集合。通常我们建立 tuples 的初衷就是不希望其中的数据被别人更改。
ii. 建立 tuples
使用()来建立
t = (1,2,3,4,5)
or
t = tuple((1,2,3,4,5))
>>>len(t)
3
tuples 可以存储不同的数据形式
t = ('one',2)

Beyond Joy Education – Confidential – Internal Distribution


24
tuples 几个基本方法
tuples.index()

>>>t.index(‘one’)
0

>>>t.count(2)
1

Method Description
count() Returns the number of times a specified value occurs in a tuple
index() Searches the tuple for a specified value and returns the position of where it was found

D. Sets
i. 最重要的特性-不重复性
ii. 初始化
thisset = {"apple", "banana", "cherry"}
print(thisset)

set.add()增加值,
thisset = {"apple", "banana", "cherry"}
thisset.add("orange")
thisset = {"apple", "banana", "cherry"}
thisset.update(["orange", "mango", "grapes"])
thisset = {"apple", "banana", "cherry"}
thisset.remove("banana")

clear()
discard()(discard(d1), if d1 not exists in s1, do nothing, otherwise remove
from d1)

copy()(Note it is a copy, so changes to the original don't effect the copy)

difference(), * difference_update (s1.difference_update(s2)会返回 s1 中除去与 s2 重


复的元素之后剩下的元素)

Beyond Joy Education – Confidential – Internal Distribution


25
S1.intersection(s2) ,返回 overlap 元素组成的新 set,s1.intersection_update(s2) – 将
s1 与 s2 的重复部分 update s1.

S1.isdisjoint(s2) – 判断 s1 与 s2 是否没有交集 s1.issubset(s2) – 判断 s1 是不是 s2 的子集


s1.issuperset(s2) - 判断 s1 是不是 s2 的超集

S1.union(s2)将两个集合 union 起来

S1.update(s2)将 s1 update 为 s1 union s2

iii. 利用 Set 的不重复性进行操作

例 22. 写一个程序判断某个 list 中是否存在 duplicate 值,如:


Input: [1,2,3,1]
Output: true

Input: [1,2,3,4]
Output: false

Input: [1,1,1,3,3,4,3,2,4,2]
Output: true

我们先不考虑其他的,遍历整个 list 来寻找 duplicate 值的算法,set 的不重复性的特点可以帮我们用一行语句来实现这一功能:


list_num = [1,1,1,3,3,4,3,2,4,2]

>>>set(list_num)
{1, 2, 3, 4}
>>>len(set(list_num))
4
>>>len(list_num)
10
不难发现,如果给定的 list 中存在重复值,那么 len(set(list))返回的长度一定小于直接用 len(list)返回的长度值。不难写出
函数如下,可以看出,一行代码就实现了想要的功能。
def containsDuplicate(list_num):
return len(set(list_num)) == len(list_num)

在学习了这些数据和变量类型之后,我们再来看一看常见的类型转换函数,我们已经学习了这其中的大部分内容,其他的函数用法也很相似。

函数 作用

int(x [,base]) 将 x 转换为一个整数

long(x [,base] ) 将 x 转换为一个长整数

Beyond Joy Education – Confidential – Internal Distribution


26
函数 作用

float(x) 将 x 转换到一个浮点数

complex(real [,imag]) 创建一个复数

str(x) 将对象 x 转换为字符串

repr(x) 将对象 x 转换为表达式字符串

eval(str) 用来计算在字符串中的有效 Python 表达式,并返回一个对象

tuple(s) 将序列 s 转换为一个元组

list(s) 将序列 s 转换为一个列表

set(s) 转换为可变集合

dict(d) 创建一个字典。d 必须是一个序列 (key,value)元组。

frozenset(s) 转换为不可变集合

chr(x) 将一个整数转换为一个字符

unichr(x) 将一个整数转换为 Unicode 字符

ord(x) 将一个字符转换为它的整数值

hex(x) 将一个整数转换为一个十六进制字符串

oct(x) 将一个整数转换为一个八进制字符串

LESSON 4. BOOLEAN、逻辑表达、IF 条件语句


A. Boolean – False values in Python:
The following elements are false:
1) None
2) False
3) 0 value (whatever type from integer, float to complex)
4) Empty collections: “”, (), [], {}
B. >,>=,<,<=,==,!= Operators
以下是 python 中的比较运算符列表,我们接下来一一涉及。

运算符 描述

== 等于 - 比较对象是否相等

!= 不等于 - 比较两个对象是否不相等

<> 不等于 - 比较两个对象是否不相等

Beyond Joy Education – Confidential – Internal Distribution


27
运算符 描述

> 大于 - 返回 x 是否大于 y

小于 - 返回 x 是否小于 y。所有比较运算符返回 1 表示真,返回 0 表示假。这分别与特殊的变量 True 和 False 等价。注意,这些变


<
量名的大写。

>= 大于等于 - 返回 x 是否大于等于 y。

<= 小于等于 - 返回 x 是否小于等于 y。

i. Try 10 == 10, 5<=8, 1!=2


ii. a = 1, b = 2
尝试进行将 a,b 与上表中的每个逻辑比较运算符进行组合并查看返回值
iii. Chaining comparison Operators:
>>> x = 2
>>> 1 < x < 3
True
>>> 10 < x < 20
False
>>> 3 > x <= 2
True
>>> 2 == x < 4
True
C. and, or, not
i. and 从左向右判断,如果所有 values 都为 True,则返回返回最后一个 value(True) 如果任意一个为
False,则返回第一个 False,不再继续向后判断
ii. or 返回第一个 True value,如果所有 values 都为 False,返回最后一个 value(False)
D. in/not in 成员运算符,判断某值是否存在于某一 list/string
i. 可以应用于 string,list, tuple
ii. 举例如下

#string
>>> ‘name’ in ‘My name is Kevin.’
True
#list
>>>a, b= 3, 6
>>>mylist = [1,2,3,4,5]
>>>a in mylist
True
>>>b in mylist
False
Beyond Joy Education – Confidential – Internal Distribution
28
#tuples
>>>x = 10
>>>x in (10,20)
True
E. 逻辑判断的执行顺序,如果不确定,则加括号
具体的执行顺序请看下表
operators descriptions
(), [], {}, ‘’ tuple, list, dictionnary, string
** exponent
*, /, % multiplication, division, modulo
+, - addition, substraction
<, <=, >=, > comparison operators
==, !=, is, is not, in, comparison operators (continue)
not in comparison operators (continue)
not boolean NOT
and boolean AND
or boolean OR
lambda lamnda expression

课堂练习:
2<=3>=1
True
2<3>10
False
12!=12
False
4>=2 and 3!=1 or 5<3
True
12>6 or 3!=2 and 1>2
False
F. If Statements
i. 何时使用 IF 语句
老婆打电话给程序员老公说,回家路上买一斤包子,如果看到葱,买一个
一般人:买回家一斤包子和一颗葱
程序员:买了一个包子

IF 语句的执行如下图:

Beyond Joy Education – Confidential – Internal Distribution


29
Python 编程中 if 语句用于控制程序的执行,基本形式为:
if 判断条件:
执行语句……
else:
执行语句……
If hour > 8 and hour < 19:
print(“you are being transferred to an agent”)
If age <12 or age > 65:
print(“This game is not for you”)
If not char in “abcdefghijklmnopqrstuvwxyz”:
print(“This is not a lower case letter ”)

ii. Elif, Else 的使用


answer = 'A'
user_input = input('Please enter your choice in A,B,C and D').upper()
if user_input == 'A':
print('You got the right answer')
elif unser_input in ['B', 'C', 'D']:
print('Sorry, you did not get the right answer')

Beyond Joy Education – Confidential – Internal Distribution


30
else:
print('Invalid answer!')
课堂练习 1 - Guess a number:
num = int(input("Please input an integer between 1 and 10 "))
num = int(input("Please input an integer between 1 and 10 "))
answer = 5
if num != answer:
if num < answer:
print("Please guess higher")
num = int(input())
else:
print("Please guess lower")
num = int(input())
if num == answer:
print("Good job!")
else:
print("Sorry, you did not get the correct answer")
else:
print("Wow! You get it first time!")
课堂练习 2
Write a program, ask the user to input an amount they were billed. If the
bill amount is greater than $20, then print” You can use credit card or cash
to pay” If it is less than $20 and greater than $0, then print”You can only use
cash to pay” If the amount entered is less than zero, print”You have entered
a wrong amount”

LESSON 5. 循环变量和循环语句、FOR LOOP


A. 编写程序来解决问题的初衷之一- 使用计算机完成 repetitive work. 大量重复而有规律可循的工作,如我们想要输出某一
string 中的每个字符,或者提取某个 list 中的每一个数值,都可以通过循环 loop 来完成,for loop 是最基本而且最常用的一
种。
B. for-loop 适用的情况 – for 循环是用来在每次迭代时,执行相同的代码的循环(execute a block of code in
every iteration)
C. – strint, list, tuplt, 甚至可以为 dictionary
D. 使用 For 循环的情况,For 循环的基本格式
for item in object:
statements to do something

例 1. 循环输出变量 i 的值
for i in range(0,10):
print('i is',i,'now')
Python 中 For loop 的特性,可以直接遍历成员,并不必须使用 index

Beyond Joy Education – Confidential – Internal Distribution


31
例 2. 循环提取某一 string 中的数字
class_size = "We have four classes with 6,8,7,7 students respectively"
student_count = 0
for char in class_size: #不需要 index,直接遍 历 string 中的每一个成员
if char in '0123456789':
student_count = student_count + int(char)
print("We have in total {} students".format(student_count))

例 3. 通过 for-loop 找出一个 list 中的偶数:


For num in num_list:
If num % 2 == 0;
Print(num)
Else:
Print(“This is an odd number”)
E. 在 String,List 中分别如何使用 For 循环,使用 range()来实现数字循环变量的使用。由于 for 循环可以直接遍历成员,我
们可以通过这样的方式提取 string 中的某些变量
for char in my_string:
if char in ‘0123456789’:
print(char)
也可以通过整数 Index 的方式来遍历:
for I in range(len(my_string)):
if my_string[i] in ‘0123456789’:
print(my_string[i])
F. Tuple 循环
普通用法 – 遍历 tuple 中每一个元素
For top in a:
print(top)
由于 tuples 存在 unpacking 特性,我们可以利用这一性质查看 tuples 中的内部成员值
my_tuple = [(2,4),(6,8),(10,12)]
for (v1,v2) in my_tuple:
print(v1)
print(v2)
此处将 tuples unpacking 与 for loop 结合,在循环的过程中每一步都经历了一个 unpacking 的过程
G. Dictionary 的循环

例 4.
d = {‘x1’:15,’x2’:10,’x3’:22}
for item in d:
print(item)
x1
x2
x3

Beyond Joy Education – Confidential – Internal Distribution


32
由上面的例子可以看出,如果直接循环遍历一个 dictionary 里面的成员,则返回的只是每一个 key 的名称。并没有显示对应的
value
在 python 中,如果想要对字典关键字进行循环,则应用 dict.keys()

例 5.
d = {‘x1’:15,’x2’:10,’x3’:22}
for key in d.keys():
print(key)
相似地,我们可以找到对每个关键字对应的值 的循环,使用 dict.values() 可以遍历其中的 value

例 6.
d= {‘x1’:15,’x2’:10,’x3’:22}
for value in d.values():
print(key)
如果我们想要遍历 dictionary 中的成员(包含关键字和对应的值)则可以使用 dict.items()

例 7.
d= {‘x1’:15,’x2’:10,’x3’:22}
for item in d.items():
print(item)
此处,同样可以使用 dictionary 的 unpacking 特性,同时遍历 keys 与 values
for key,value in d.items():
print(key,end =': ') #此处更改了 print 的结束符,默认为换行符’\n’
print(value)
课堂练习 1 , a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13]
写一个程序,返回 a 和 b 中共有的元素(非重复)
课堂练习 2,
A shift on A consists of taking string A and moving the leftmost character to the
rightmost position. For example, if A = 'abcde', then it will be 'bcdea' after one
shift on A. Return True if and only if A can become B after some number of
shifts on A.

Example 1:
Input: A = 'abcde', B = 'cdeab'
Output: True

Example 2:
Input: A = 'abcde', B = 'abced'
Output: False

课堂练习 3,

Beyond Joy Education – Confidential – Internal Distribution


33
Say you have an array for which the ith element is the price of a given stock on
day i.
If you were only permitted to complete at most one transaction (i.e., buy one
and sell one share of the stock), design an algorithm to find the maximum
profit.
Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
含义:在第二天的时候以 1 的价格买进,在第五天的时候以 6 的价格卖出,可以获得这一时间段上的最大利润 5
Input: [7,6,5,3,2,1]
Output: 0
此时,不存在盈利的可能性,返回 0

LESSON 6. 当型循环 – WHILE LOOP


A. 使用 while 的情况,while 循环的基本格式
while 用于循环执行程序,即在某个条件成立的情况下,持续执行某段代码。 例如,如果今年夏天没有瘦掉五斤,则继续坚持每天运动。
再比如,如果一天没有写满一百行代码,则继续写下去。
条件表达式是一个逻辑表达式,必须返回一个 true 或者 false 值。while 循环的基本格式为:
while 判断条件:
执行语句

例 1. 数字初始值为 0,使用 while 循环,当数字小于 5 的时候打印数字。


number = 0
while number < 5:
print('number is now',number)
number = number + 1

思考:如果把代码中最后一行 number = number + 1 去掉会怎么样?


当循环语句中的判断条件永远为 true,循环将永远进行下去,变成无限循环。上例中如果没有最后一行,number 一直为初始值
0,判断语句 0<5 永远成立,循环将变成无限循环,所以在代码最后要更新 number 值。更新 number 的方法除了
number = number + 1 以外,我们也可以用 number += 1 来表达,更加简洁。
B. while – else 的写法及练习
我们也可以把 else 语句和 while 循环结合,当判断条件为 false 的时候执行 else 语句块。和之前同样的例子,如果今年夏
天瘦掉了五斤,则疯狂大吃一顿。基本格式为:
while 判断条件:
执行语句
else:

Beyond Joy Education – Confidential – Internal Distribution


34
另一个执行语句

例 2. 数字初始值为 0,使用 while 循环,当数字小于 5 的时候打印数字。当数字不小于 5,打印“数字不小于 5”。


number = 0
while number < 5:
print('number is now',number)
number += 1
else:
print('Number is no less than 5')

思考:其他代码不变,如果数字初始值为 100 呢?
如果 number 等于 100,判断条件 100<5 吗?不成立,执行 else 语句,直接输出数字不小于 5。
C. 循环中的命令语句 continue, break, pass
continue: 跳出本次循环
break:结束整个循环
pass: 什么都不做,只是起到占位的作用。

例 3. 给定一列数,输出其中所有不能被 3 整除的数
list1 = [1,2,3,4,5,6,7,8,9,10,11]
i=0
while i < len(list1):
if list1[i] % 3 == 0:
i = i +1
判断为真
continue
print(i)
i=i+1
continue
可以看出,continue 起到的作用是跳出当次循环,回到 while 位置,位于 continue 后面的 print(i)就没有得到执行

例 4. Break - 给定一列数,找到其中的第一个偶数
list2 = [3,5,7,11,14,21,18]
i=0
while i < len(list2):
if list2[i] % 2 == 0:
print(list2[i])
break
i=i+1

print('The i is now',i)

14
The i is now 4

Beyond Joy Education – Confidential – Internal Distribution


35
可以看到,此程序在找到满足 if statements 的数字之后,输出了该数字,执行了 break 语句,跳出循环,因此 i 的值并没有
继续循环增长下去,而是停在 4 的位置。
课堂练习
1 , 使用 while loop 打印出 50 以下所有奇数的和
2,从键盘输入 10 个数字,最后打印出平均值
3,从键盘输入一个整数,返回其阶乘,如键盘输入 5,返回 5! = 120
4,从键盘请求数字,直到键盘输入字母 q 为止,计算所有数的和与乘积

LESSON 7. 函数 FUNCTION, BUILT-IN FUNCTIONS 与迭代 RECURSION


A. 函数是什么:
在之前的课程中,其实我们已经用到了各种各样的函数,从最基本的 print(), type()到一些模块内置的函数等等。
函数是一个代码段,用来实现一种或几种相关联的功能,具有可重复使用的特点,把需要反复调用的一段代码编写成函数的形式,可以让整段
代码可读性,可维护性大大提高。
B. 函数的固定格式
def function_name(parameters):
'''
函数的最开头注释中,一般存放函数使用说明
'''
statements of the function
return [expression]
可以看到函数的编写格式比较固定,开头以 def 开始,后接函数名,输入变量和参数放在函数名后紧跟的括号中,冒号后面试函数正文(此
处一定要注意缩进),最后返回一个值(不一定是数值,可以是 list, dictionary 或者用户自定义的类),如果不设置返回值,则
返回 None。

例 1. 一个简单的函数
def hello():
print("Hello world")
>>> hello()
Hello world

例 2. 带有输入参数的函数
def hello(name):
print(("Hello",name))
>>>hello('Kevin')
Hello Kevin
例: 带有返回值的函数
def add_num(a,b):
return a+b
>>>print(add_num(1,2))
3

Beyond Joy Education – Confidential – Internal Distribution


36
例 3. 带有循环的函数举例- 判断是否为质数
def is_prime_number(num):
for i in range(2, num):
if num % i == 0:
print(num, 'is not a prime number')
else:
print(num, 'is a prime number' )
>>>is_prime_number(11)
11 is a prime number
>>>>is_prime_number(18)
18 is not a prime number

例 4. 带有循环的函数举例 2 – 判断一个 list 中偶数有几个


def count_even_number(list_num):
count = 0
for num in list_num:
if num % 2 == 0:
count += 1
return count
>>>list1 = [3,4,2,6,5,9]
>>>count_even_number(list1)
3
C. *args, **kwargs
含义 – arguments, keyword arguments

作用 – ?
先来看一个例子
def sum_num(a,b):
return sum((a,b))
>>>sum_num(2,3)
5
我们想要自定义一个为所有输入参数求和的函数,如果我们知道有且只有两个输入参数的时候,我们可以按照上述方式进行定义。但如果我们
不知道有几个输入参数呢?
可以使用类似穷举的方法,在定义中加入一系列输入参数并赋予初始值 0
def sum_num(a=0,b=0,c=0,d=0,e=0,f=0):
return sum((a,b,c,d,e,f))
>>>sum_num(2,3,4,5)
14
>>>sum_num(1,4,6)
11
这种方式固然可行,但是可以看出并不是一个好的方法,代码的效率不高,看起来也不够整洁有效。
因此我们引入*args

Beyond Joy Education – Confidential – Internal Distribution


37
*args – 当函数的输入参数名前有一个*符号时,此函数允许任意数量的输入参数,函数会以一个 tuple 的形式接收所有输入参数。
def sum_num(*args):
return sum(args)
>>>sum_num(2,3,4)
9
**kwargs – 与 args 的用法类似,只是顾名思义,此时的 arguments 是 keyworded 即带有关键字的输入参数,
此时函数会创建一个 dictionary 来接收这样的 keyworded arguments.
def count_accounts(**kwargs):
if 'account' in kwargs:
print('You have in total {} accounts'.format(kwargs['account']))
else:
print('There is no account under your name')
>>>count_accounts(account = 4)
You have in total 4 accounts
同时使用*args 与 **kwargs 的时候,*args 必须写在**kwargs 之前
def my_func(*args, **kwargs):
if 'length' and 'classes' in kwargs:
print('This class includes {0} and {1}.'.format(args[0],args[1]))
print('Each class lasts {0} hours and there are {1} classes in
total'.format(kwargs['length'],kwargs['classes']))
else:
print('This class includes {0} and {1}.'.format(args[0],args[1]))
print('The length of class has yet to be announced')

>>>my_func('Python','SQL',length = 4,classes = 10)


This class includes Python and SQL.
Each class lasts 4 hours and in total 10 classes
D. *匿名函数 lambda 与 map, filter 的使用
有时候我们想要实现一行代码的重复使用,却又不想费劲去写一个函数,这时候我们可以考虑使用匿名函数 anonymous
functions – 即 lambda 表达式
lamda 表达式所含有的内容通常与我们写在函数中的 return 部分相像,是一行代码,并可以计算并返回某一值。
x = lambda a : a+10
print(x(5))

x = lambda a, b : a * b
print(x(5, 6))

x = lambda a, b, c : a + b + c
print(x(5, 6, 2))

map 的使用
map(function_to_apply, list_of_inputs)

Beyond Joy Education – Confidential – Internal Distribution


38
复杂的函数应用:

items = [1, 2, 3, 4, 5]
squared = []
for i in items:
squared.append(i**2)
通过 map 的方式,可以将其简化为
squared = list(map(lambda x: x**2, items))
更可以将多个函数组合起来应用于一个 list
def multiply(x):
return (x*x)
def add(x):
return (x+x)

funcs = [multiply, add]


for i in range(5):
value = list(map(lambda x: x(i), funcs))
print(value)
filter 的用法,顾名思义,即筛选
number_list = range(-5, 5)
less_than_zero = list(filter(lambda x: x < 0, number_list))
print(less_than_zero)

reduce 的用法:大大简化代码的写法
product = 1
list = [1, 2, 3, 4]
for num in list:
product = product * num

# product = 24
使用 reduce 可以写为:
from functools import reduce
product = reduce((lambda x, y: x * y), [1, 2, 3, 4])

例 5. 计算输入值得平方 – 使用函数的写法
def square(num):
squared_num = num ** 2
return squared_num
上述函数其实可以写成一行
def square(num): return num ** 2
此时我们就可以考虑使用 lambda 表达式来代替函数了,相应的 lambda 表达式如下:

Beyond Joy Education – Confidential – Internal Distribution


39
lambda num: num ** 2
那么 lambda 一般在何时使用?我们今天要讲的 map 和 filter 函数就是最经常结合 lambda 使用的两个内建函数
map(function, iterable1, iterable2,…)
map 的第一个输入变量为一个函数对象,包括普通的 def 函数和匿名的 lambda 函数,然后 map 会将此函数应用的之后的
每一个 iterable 中,最后返回一个 list,包含了在应用过 function 之后的所有 iterable 结果。
def square(x):
return x ** 2
>>>map(square, [1, 2, 3, 4])
[1, 4, 9, 16]
不难联想到,我们可以在 map 中直接加入 lambda 表达式,使得代码更加简洁
>>>map(lambda x: x ** 2,[1,2,3,4])
[1,4,9,16]
另外一个今天要简单介绍的内置函数名叫 filter,它与 map 类似,只是它接收的 function 输入参数返回值需为 Boolean
值,而 filter 返回筛选后为 True 的成员。
def is_even(num):
return num % 2 == 0
>>>nums = [1,2,3,4,5,6,7,8]
>>>list(filter(is_even,nums))
[2,4,6,8]
同样的,可以将 lambda 与 filter 结合使用,上面的这一系列代码可以简写为下面这样一句
>>>list(filter(lambda x : x % 2 == 0,nums))
[2,4,6,8]
可见,lambda 表达式在提高简洁度方面的作用。
课堂练习:
1. Write a Python function to find the Max of three numbers.
2. Write a Python function to sum all the numbers in a list.
3. Write a Python function to multiply all the numbers in a list.
4. Write a Python function to check whether a number is in a given range
5. Write a Python function that accepts a string and calculate the number of upper
case letters and lower case letters.
6. Write a Python function that takes a number as a parameter and check the
number is prime or not.
7. Write a Python program that accepts a hyphen-separated sequence of words as
input and prints the words in a hyphen-separated sequence after sorting them
alphabetically.
Sample Items : green-red-yellow-black-white
Expected Result : black-green-red-white-yellow
8. Write a Python function that checks whether a passed string is palindrome or
not.

E. built-in modules and functions

Beyond Joy Education – Confidential – Internal Distribution


40
i. math module
sqrt 平方根
exp 自然对数底 e 的 x 次幂
log 自然对数
log10 以 10 为底的对数
sin 正弦函数
cos 余弦函数
pow pow(x,y)即 x 的 y 次方
degrees degrees(x) = pi/180*x
radians radians(x) = 180/pi*x
fabs 绝对值
ii. time 的函数 clock and sleep
time 模块中有两个很重要的函数,clock 和 sleep
clock()返回当前系统的时间,通过前后两次使用 clock,可以计算程序运行的总时长,为我们之后降低时间复杂度,优化程序结构
而用。如下是一个计算你反应时间的程序
from time import clock
print('Please enter your name: ')
start_time = clock()
name = input()
end_time = clock()
print('Hi',name, 'it took you',end_time-start_time,'seconds to respond.')

sleep(t) 系统休眠 t 秒,可以让暂缓程序运行,给用户一个查看和反应的时间。下面是一个十秒倒计时的程序

from time import sleep

for count in range(10, -1, -1):


print(count)
sleep(1)
iii. Random 模块常用函数,randint, randrange,choice
from random import random, randrange, choice
>>>random()

>>>randrange(1,10,2)

>>>choice([1,2,3,4,5])

>>> choice('abcdefg')

Beyond Joy Education – Confidential – Internal Distribution


41
F. 递归 Recursion*
i. 递归算法
是一种直接或者间接调用自身函数或方法的算法。
基本思想是,把一个大的问题转化成若干个小的,与原问题相似的问题来求解
几个特点:
1) 在方法(函数)中调用自身
2) 一定有一个递归结束的条件,否则递归将无限次进行下去
3) 递归算法的代码会很简洁,但是运行效率低,一般不使用递归来设计程序
4) 在递归调用的过程中,系统在每一层递归时都要开辟新的内存空间来存储数据,因此递归在存储效率上也比较低,而且容易溢出,
这也是另一个我们不提倡递归的原因
综上所述,递归算法是一种比较低效,但是掌握了递归的思想可以让我们快速写出简洁的代码,并锻炼我们逆向思考的能力。下面我们举两个
简单的例子来介绍一下递归
ii. 经典递归例子——阶乘
计算用户输入数值的阶乘(factorial)
计算阶乘是递归程序设计的一个经典示例。计算某个正整 e 数的阶乘就是用那个数去乘包括 1 在内的所有比它小的整数。例如 5 的阶乘
5! = 5*4*3*2*1
用递归的思想,我们可以想到一个算法
5! = 5*4!
4! = 4*3!
3! = 3*2!
2! = 2*1!
1! = 1 此处为递归出口
因此我们可以写出函数如下
def factorial(n):
if n == 1:
return 1
else:
return n*factorial(n-1)
>>>factorial(5)
120
不难看出,我们先设置了递归的出口 n == 1 时,返回常数 1。然后对于其他的输入参数,我们调用了此递归函数本身来进行计算。
iii. 经典递归例子——斐波那契数列
斐波那契数列的排列是:1,1,2,3,5,8,13,21,34,55,89,144…后一个数等于前面两个数的和。
可以总结出以下的公式:
F0 = 1
F1 = 1
Fn = Fn-1 + Fn-2
不难看出,斐波那契数列的推导过程本身就是一个递归的过程,因此我们可以很容易写出以下的递归函数
def fibonacci(n):
if n == 0 or n == 1:

Beyond Joy Education – Confidential – Internal Distribution


42
return 1
else:
return fibonacci(n-1)+fibonacci(n-2)

for i in range(15):
print(fibonacci(i),end = ' ')

#Output 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610


简单易得的函数,但是写完之后我们回头看这个函数,会发现有明显的低效之处,在哪里呢?
首先,尝试计算 fibonacci(100)
程序的反应时间反应时间很长,这是为什么呢?从函数本身的写法可见端倪。观察函数 else 后面执行的步骤,可以看出,每次在计算
fibonacci(n)的时候,都要调用一边 fibonacci(n-1)与 fibonacci(n-2),而一旦里面的 n 值较大,调用此函数
的次数就会指数级增长,而我们发现,fibonacci(n-1)在进行计算的时候,返回 fibonacci(n-2)与
fibonacci(n-3),这其中的 fibonacci(n-2)其实我们已经计算过一遍了,这里相当于重复了一边计算。指数级增长的调用
次数加上对同一函数的重复计算,都导致了递归算法的低效。那么我们可以用什么算法来替代呢?
def fib(n):
a,b = 0,1
i=0
while i < n:
a,b = b,a+b
i += 1
return a

for i in range(15):
print(fib(i),end = ' ')

>>>fib(100)
354224848179261915075
我们凭直观感受就可以知道,这样的写法大大提高了效率,缩短了程序的运行时间

总结:借助递归的思想,我们可以用简洁的语句实现复杂的功能,这在一些较为复杂的问题中很有意义,如二叉树的排序等,但是平时在应用
递归时,我们需要加倍小心,简洁的代码可能是以程序运行效率为牺牲品换来的。至于复杂程序中的递归,如二叉树,链表的递归,在初级课
程中我们就暂时不涉及了。
课堂练习:
1. Write a Python program of recursion list sum
Test Data: [1, 2, [3,4], [5,6]]
Expected Result: 21
2. Write a Python program to get the sum of a non-negative integer.
Test Data:
sumDigits(345) -> 12
sumDigits(45) -> 9

Beyond Joy Education – Confidential – Internal Distribution


43
LESSON 8. 模块 – 以 DATETIME,PANDAS,NUMPY 为例

什么是 PYTHON 中的模块?


A. Python 模块 Python 模块(Module),是一个 Python 文件,以.py 结尾,包含了 Python 对象定义和
Python 语句。 模块让你能够有逻辑地组织你的 Python 代码段。 把相关的代码分配到一个模块里能让你的代码更好用,更易懂。
比如我们之前已经接触过的 random, time 模块等
B. Python 中的 datetime module
使用 datetime module,可以统一日期格式,便于时间的加减,求差,时区转换等的计算。导入方式:import
datetime。
datetime.time
我们可以使用 datetime.time 来创建时间,需要传递的参数为:hour, minute, second,
microsecond, tzinfo(时区信息)。

例 1. 创建时间 5 小时 15 分钟 4 秒
import datetime
t = datetime.time(5, 15, 4)
print(t)
# 05:15:04
调用时间的小时,分钟,秒,微秒,时区属性信息
print('hour:', t.hour)
print('minute:', t.minute)
print('second:', t.second)
print('microsecond:', t.microsecond)
print('tzinfo:', t.tzinfo)
#hour: 5
minute: 15
second: 4
microsecond: 0
tzinfo: None
datetime.date
与 datetime.time 类似,我们可以使用 datetime.date 创建日期,需要传递的参数为 year, month,
day。这种类型不能处理时分秒。

例 2. 调用方法.today 创建今天的日期
today = datetime.date.today()
print(today)
#2018-08-05
print('ctime:', today.ctime())
#ctime: Sun Aug 5 00:00:00 2018
print('ordinal:', today.toordinal())
#ordinal: 736911

Beyond Joy Education – Confidential – Internal Distribution


44
#返回日期是是自 0001-01-01 开始的第多少天

例 3. 查看 today 中的属性年、月、日信息
print('Year:', today.year)
print('Month:', today.month)
print('Day:', today.day)
#Year: 2018
#Month: 8
#Day: 5

例 4. 调用.replace 方法替换日期
d1 = datetime.date(2015, 4, 15)
print('d1:', d1)
d2 = d1.replace(year=2018)
print('d2:', d2)
#d1: 2015-03-11
#d2: 1990-03-11

例 5. 举例:使用上例中的数据计算两个日期的差值
d1-d2
#datetime.timedelta(1096)
datetime.datetime
Datetime 模块下的日期时间类,可以理解为 datetime.time 和 datetime.date 的组合类。创建时间日期混
合变量需要传递的参数为 year, month, day, hour, minute, second, microsecond,
tzinfo。

例 6. 举例:调用方法 .now 创建今天的日期时间


dt = datetime.datetime.now()
print(dt)
#datetime.datetime(2018, 8, 5, 11, 42, 21, 137834)
#在没有指定 tz 参数的情况下,方法.now 和方法.today 的输出结果是一样的
print('Weekday:',dt.weekday())
print('Time:',dt.time())
print('Date:',dt.date())
print('Year:',dt.year)
print('Minute:',dt.minute)
#Weekday: 6
#Time: 11:42:21.137834
#Date: 2018-08-05
#Year: 2018
#Minute: 42

例 7. 将时间字符串转换为 datetime 对象

Beyond Joy Education – Confidential – Internal Distribution


45
datetime.datetime.strptime('2018/03/04 11:45', '%Y/%m/%d %H:%M')
#datetime.datetime(2018, 3, 4, 11, 45)

sample_date = datetime.datetime(2018, 3, 4, 11, 45)


datetime.datetime.strftime(sample_date, '%Y/%m/%d %H:%M')
%a Locale’s abbreviated weekday name.
%A Locale’s full weekday name.
%b Locale’s abbreviated month name.
%B Locale’s full month name.
%c Locale’s appropriate date and time representation.
%d Day of the month as a decimal number [01,31].
Microsecond as a decimal number [0,999999], zero-padded
%f
on the left
%H Hour (24-hour clock) as a decimal number [00,23].
%I Hour (12-hour clock) as a decimal number [01,12].
%j Day of the year as a decimal number [001,366].
%
Month as a decimal number [01,12].
m
%M Minute as a decimal number [00,59].
%p Locale’s equivalent of either AM or PM.
%S Second as a decimal number [00,61].
Week number of the year (Sunday as the first day of the
%U
week)
%w Weekday as a decimal number [0(Sunday),6].
% Week number of the year (Monday as the first day of the
W week)
%x Locale’s appropriate date representation.
%X Locale’s appropriate time representation.
%y Year without century as a decimal number [00,99].
%Y Year with century as a decimal number.
%z UTC offset in the form +HHMM or -HHMM.
%Z Time zone name (empty string if the object is naive).
%
A literal '%' character.
%
datetime.timedelta
使用 datetime.timedelta 来表示两个不同时间之间的差值,它可以对 datetime.date,
datetime.time 和 datetime.datetime 对象做算术运算。

例 8. 调用方法 .now 创建今天的日期时间,并且使用 datetime.timedelta 返回四天后、四天前、四小时后、四小


时三十分钟后的日期时间
dt = datetime.datetime.now()
dt+datetime.timedelta(4)
dt+datetime.timedelta(-4)

Beyond Joy Education – Confidential – Internal Distribution


46
dt+datetime.timedelta(hours=4)
dt+datetime.timedelta(hours=4,minutes = 30)

例 9. 计算两个日期时间的差值,并且返回相差的秒数
dt2 = dt + dt+datetime.timedelta(minutes=10)
dt3 = dt2-dt
dt3.seconds
C. Python 中的 numpy 模块
Numpy 模块的作用 – 科学化数学计算,向量化运算,矩阵化运算初步,以及与其他数据分析包的结合。
A numpy array is a grid of values, all of the same type, and is indexed by a tuple of
nonnegative integers. The number of dimensions is the rank of the array; the shape of an
array is a tuple of integers giving the size of the array along each dimension.

a = np.array([1, 2, 3])
print(type(a))
print(a.shape)
print(a[0], a[1], a[2])
a[0] = 5
print(a)
b = np.array([[1,2,3],[4,5,6]])
print(b.shape)
print(b[0, 0], b[0, 1], b[1, 0])
建立 numpy array 常用几种不同的初始化方式
a = np.zeros((2,2)) # Create an array of all zeros
print(a)
b = np.ones((1,2)) # Create an array of all ones
print(b)
c = np.full((2,2), 7) # Create a constant array
print(c)

d = np.eye(2) # Create a 2x2 identity matrix


print(d)

e = np.random.random((2,2)) # Create an array filled with random


values
print(e)

将多个 list 转化为多维的 numpy array


a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
b = a[:2, 1:3]
print(a[0, 1])
b[0, 0] = 77

Beyond Joy Education – Confidential – Internal Distribution


47
print(a[0, 1])
index 引用 numpy array 中的元素
a = np.array([[1,2], [3, 4], [5, 6]])

print(a[[0, 1, 2], [0, 1, 0]])

# The above example of integer array indexing is equivalent to this:


print(np.array([a[0, 0], a[1, 1], a[2, 0]]))

# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]])

# Equivalent to the previous integer array indexing example


print(np.array([a[0, 1], a[0, 1]]))

# Create a new array from which we will select elements


a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(a)
# Create an array of indices
b = np.array([0, 2, 0, 1])
# Select one element from each row of a using the indices in b
print(a[np.arange(4), b])
# Mutate one element from each row of a using the indices in b
a[np.arange(4), b] += 10
print(a)

使用 boolean indexing 引用 numpy array 中的元素 – 可以用于选择 array 中满足特定条件的数据,常用于


data cleaning
a = np.array([[1,2], [3, 4], [5, 6]])

bool_idx = (a > 2)

print(bool_idx)

print(a[bool_idx])

print(a[a > 2])

numpy 有这自身独特的数据格式,比 python 自带的数据格式更加具体化

Beyond Joy Education – Confidential – Internal Distribution


48
x = np.array([1, 2])
print(x.dtype)
x = np.array([1.0, 2.0])
print(x.dtype)

x = np.array([1, 2], dtype=np.int64)


print(x.dtype)
使用 numpy,可以轻易实现矩阵运算。
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)

print(x + y)
print(np.add(x, y))

print(x - y)
print(np.subtract(x, y))

print(x * y)
print(np.multiply(x, y))

print(x / y)
print(np.divide(x, y))

print(np.sqrt(x))

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

v = np.array([9,10])
w = np.array([11, 12])

print(v.dot(w))
print(np.dot(v, w))

print(x.dot(v))
print(np.dot(x, v))

print(x.dot(y))
print(np.dot(x, y))
numpy 还有许多自带的函数可以供我们进行简单的数据分析,举例如下

x = np.array([[1,2],[3,4]])

Beyond Joy Education – Confidential – Internal Distribution


49
# 求和
print(np.sum(x)) # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0)) # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1)) # Compute sum of each row; prints "[3 7]"

# 求平均
print(np.mean(x))

#求 sin,cos
print(np.sin(x))
print(np.cos(x))

#对矩阵求转置
print(x.T)

D. Python 中的 pandas 模块
Pandas 是基于 numpy 所构建的,为时间序列分析,矩阵分析,数据可视化提供更好支持的模块,包含两种数据结构,
Series 与 DataFrame

Series 类似于一维数组与字典(map)数据结构的结合。它由一组数据和一组与数据相对应的数据标签(索引 index)组成。这


组数据和索引标签的基础都是一个一维 ndarray 数组。可将 index 索引理解为行索引。 Series 的表现形式为:索引在左,数
据在右。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

s = pd.Series([1,3,5,np.nan,6,8])
print(s)
s = Series([1, 2, 3, 4], index = ['a', 'b', 'c', 'd'])
print(s)
#可以直接通过 Index 名来进行索引
print(s['a'])
#也可以通过 boolean indexing 方式索引
print s[s > 2]

#可以通过字典的方式直接生成
data = {'a':1, 'b':2, 'd':3, 'c':4}
x = Series(data)
#此处可以进行自定义 index

Beyond Joy Education – Confidential – Internal Distribution


50
exindex = ['a', 'b', 'c', 'e']
y = Series(data, index = exindex)

DataFrame 是一个类似表格的数据结构,索引包括列索引和行索引,包含有一组有序的列,每列可以是不同的值类型(数值、字符
串、布尔值等)。DataFrame 的每一行和每一列都是一个 Series,这个 Series 的 name 属性为当前的行索引名/列
索引名。
data = {'state':['NY', 'NJ', 'NY', 'NJ'],
'year':[2016, 2016, 2017, 2017],
'pop':[19.84, 8.98, 19.9, 9.0]}
df = pd.DataFrame(data)

#指定列索引的顺序
df = pd.DataFrame(data, columns = ['year', 'state', 'pop'])

# 自定义(index)
x = pd. DataFrame(data, index = ['d1', 'd2', 'd3', 'd4'])

下面我们将 pandas 与前面提到的 datetime 和 numpy 结合起来一起看

dates = pd.date_range('20130101', periods=6)


df = pd.DataFrame(np.random.randn(6,4), index=dates,
columns=list('ABCD'))
df2 = pd.DataFrame({ 'A' : 1.,'B' : pd.Timestamp('20130102'),
'C' : pd.Series(1,index=list(range(4)),dtype='float32'),
'D' : np.array([3] * 4,dtype='int32'),
'E' : pd.Categorical(["test","train","test","train"]),
'F' : 'foo' })
print(df2)
print(df2.dtypes)

df.head()
df.tail(3)

df.index
df.columns
df.values

df.describe()

df.sort_index(axis=1, ascending=False)

Beyond Joy Education – Confidential – Internal Distribution


51
df.sort_values(by='B')

DataFrame 中的元素索引方式与之前我们学过的有一些不太相同

df['A']

df['20130102':'20130104']

df.loc[dates[0]]

df.loc[:,['A','B']]

df.loc['20130102':'20130104',['A','B']]

df.loc['20130102',['A','B']]

df.loc[dates[0],'A']

df.iloc[3]

df.iloc[3:5,0:2]

df.iloc[[1,2,4],[0,2]]

df.iloc[1:3,:]

df.iloc[:,1:3]

除了以上几种方式,pandas 也支持 boolean indexing


df[df > 0]
df[df.A > 0]
df2 = df.copy()
df2['E'] = ['one', 'one','two','three','four','three']
df2[df2['E'].isin(['two','four'])]
s1 = pd.Series([1,2,3,4,5,6], index=pd.date_range('20130102',
periods=6))
df['F'] = s1

df.loc[:,'D'] = np.array([5] * len(df))


在数据分析行业有句老话,百分之八十的时间都会花在 data cleaning 上

Beyond Joy Education – Confidential – Internal Distribution


52
df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])
df1.loc[dates[0]:dates[1],'E'] = 1
df1
df1.dropna(how='any')
df1
df1.fillna(value=5)
pd.isna(df1)
pandas 中自带的许多功能,对我们的数据分析都很有帮助
df.mean()

df.mean(1)

df.apply(np.cumsum)

df.apply(lambda x: x.max() - x.min())

ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2018',
periods=1000))
ts = ts.cumsum()

ts.plot()

df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index,


columns=['A', 'B', 'C', 'D'])
df = df.cumsum()

plt.figure()
df.plot()
plt.legend(loc='best')
掌握了这些之后,我们就可以进行一些简单的数据分析了

LESSON 9. 正则表达式 REGULAR EXPRESSION


A. 正则表达式的介绍
正则表达式 – 特殊的字符序列,能够检查某一个字符串是否与某种特定的字符串模式相匹配

pattern1 = "cat"
pattern2 = "bird"
string = "dog runs to cat"
print(pattern1 in string) # True
print(pattern2 in string) # False

Beyond Joy Education – Confidential – Internal Distribution


53
# 使用正则表达式进行匹配,返回的结果如下
import re

# regular expression
pattern1 = "cat"
pattern2 = "bird"
string = "dog runs to cat"
print(re.search(pattern1, string))
print(re.search(pattern2, string))

正则表达式模块在 Python 中为 re,因此使用时直接 import re 即可应用全部功能


常用的功能如下:
模式匹配 Pattern matching (在某一个字符串中寻找与特定字符串模式相匹配的)
替换 substitution (在某一个字符串中寻找到符合特定模式的字符后将其替换)
分割 splitting (将字符串按照某种模式分割)
B. 常用的正则表达式方法
1. re.compile(pattern,flags=0) 函数根据一个模式字符串和一些特定的字符参数生成一个正则表达式对象。该对象拥有
一系列方法用于正则表达式的查找,匹配和替换等功能。
flags 可以用来更改正则表达式的匹配方式,如是否忽略大小写,是否要进行多行匹配等。具体参见下表。
flag
含义
s
re.I 忽略大小写
re.L 使用本地化识别(local-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据 Unicode 字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 增强可读性,忽略空格和#后面的注释
注:如果想要加上多个 flags 标志符,可以用'|'符号将其隔开,如 flags=re.I|re.M
下面我们看一下几种常见的 re 模块内的方法,首先是 re.findall(pattern,string,flags=0)

例 1.
pattern = '@' #1 – 找到所有 @符号
test_string ='.@POTUS @realDonaldTrump and @UFC’s @DanaWhite in
the Oval Office earlier today at the @WhiteHouse.... '
regex = re.compile(pattern) #2 将此 pattern 转换为一个 re 对象
regex.findall(test_string) #3 使用 findall 找到所有的@符号
#返回的是一个包含所有@符号的 list
['@', '@', '@', '@', '@']

test_string ='Kevin, Michael, Milton and Mitch are playing cards.'


pattern = 'M'
Beyond Joy Education – Confidential – Internal Distribution
54
regex = re.compile(pattern)
regex.findall(test_string)

pattern = 'M[a-z]+'
regex = re.compile(pattern)
regex.findall(test_string)

注意,re.compile 一般仅用于 findall, match 和 search 方法


2. re.search(pattern,string,flags=0)对 pattern 进行查找,找到第一个匹配 pattern 的字符串位置,并
返回一个 match 对象,如果没有匹配上则返回 None

例 2.
pattern = 'term1'
text = 'The re.search is trying to find the term1 in this sentence, but not
any other terms.'
match = re.search(pattern,text)
print(match)
<_sre.SRE_Match object; span=(36, 41), match='term1'>
可以看到返回的 match object 中包含了 pattern 所在位置以及 pattern 内容的信息
3. re.match(pattern,string,flags=0) 尝试从 string 的起始位置匹配 pattern,如果不能在起始位置匹配
上,则直接返回 None

例 3.
re.match('www', 'www.python.org') #返回<_sre.SRE_Match object;
span=(0, 3), match='www'>
re.match('python', 'www.python.org') #None
4. re.sub(pattern, repl, string, count=0, flags=0) 将 string 中的 pattern 用 repl 来替换,
count 为模式匹配上之后替换的最大次数,默认情况下替换所有符合的匹配
print(re.sub(r"tough ", "easy", "Python is tough"))

5. re.split 分割
print(re.split(r"[,;\.]", "Python;SQL;Java"))
6. re.findall 找到所有符合要求的模式
print(re.findall(r"r[ua]n", "run ran runner random racket"))
print(re.findall(r"(run|ran)", "run ran runner random racket")) # | 是或的意思

C. 正则表达式模式:
模式字符串使用特殊的语法来表示一个正则表达式,通过编写一个正则表达式模式,我们可以方便地查找并匹配到想要的模式字符,在正则表
达式模式中

Beyond Joy Education – Confidential – Internal Distribution


55
1) 字母和数字表示他们自身含义。一个正则表达式模式中的字母和数字匹配同样的字符串。
2) 转义符反斜杠\, 多数字母和数字前加一个反斜杠时会拥有不同的含义。
3) 标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
4) 反斜杠本身需要使用反斜杠转义。
5) 当正则表达式中含有反斜杠时,可以通过 raw string 方式来表达,如 r'\t',等价于 '\\t'
i. 正则表达式模式中的字符表
模式 解释
^ 匹配字符串的开头
$ 匹配字符串的末尾。
. 匹配单个除了换行符之外的字符
[...] 匹配在[]中的任意一个单个字符
[^...] 匹配不在[]中的字符:[^abc] 匹配除了 a,b,c 之外的字符。
re* 匹配 0 个或多个的表达式。
re+ 匹配 1 个或多个的表达式。
re? 匹配 0 个或 1 个由前面的正则表达式定义的片段,非贪婪方式(lazy match)
re{ n} 精确匹配 n 个前面表达式
re{ n,} 匹配 n 个及 n 个以上的前面表达式
re{ n, m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式(greedy match)
a| b 匹配 a 或 b
下面我们看几个例子:

例 4.
1) ^匹配字符开头
>>>pattern = '^M'
>>>test_string = 'Kevin and Milton will attend the python class'
>>>re.findall(pattern,test_string)
['M']
下面我们看一下多行匹配的例子
string = """
Kevin is here
We are all here at the python class
"""
print(re.search(r"^W", string)) # None
print(re.search(r"^W", string, flags=re.M))

2) $匹配字符结尾
>>>pattern = 'k$'
>>>test_string = 'Here is New York’
>>>re.findall(pattern,test_string)
['k']

Beyond Joy Education – Confidential – Internal Distribution


56
3) . 匹配任何字符 (除了 \n)
pattern = '. '
test_string = 'Here is New York’
re.findall(pattern,test_string)
4) find a string starts with M and end with s, with three
characters in the middle
>>>pattern = 'M…s'
>>>test_string = 'Kevin and Mu will attend the python class'
>>>re.findall(pattern,test_string)
5) find a string starts with s, end with e and has one or more
characters in the middle
>>>pattern = 'c.+n'
>>>test_string = 'Can you can a can as a canner can can a can?'
>>> re.findall(pattern,test_string)
#注意此时返回的 list,包含的是一个长句,思考如果我们想要每一个符合要求的单词,如何操作?
6) lazy match symbol - ?
>>>pattern = 'c+?n'
>>>test_string = 'Can you can a can as a canner can can a can?'
>>> re.findall(pattern,test_string)
#加入了?符号,就将搜索模式改为了非贪婪搜索,只匹配符合要求的尽可能少的字符串
7) []
>>>pattern = '[Bb]uy'
>>>test_string = 'Bitcoin analysis – Buy the rumor and sell the news'
>>> re.findall(pattern,test_string)

# multiple patterns ("run" or "ran")


ptn = r"r[au]n" # start with "r" means raw string
print(re.search(ptn, "dog runs to cat"))
print(re.search(r"r[A-Z]n", "dog runs to cat"))
print(re.search(r"r[a-z]n", "dog runs to cat"))
print(re.search(r"r[0-9]n", "dog r2ns to cat"))
print(re.search(r"r[0-9a-z]n", "dog runs to cat")) '
8) ^[] exclude
>>>pattern = ' [^ ,.!?]+'
>>>test_string = 'Hey, do you know how we can exclude the punctuation
and spaces? The exclude symbol is a great way! '
9) 几种重复匹配的方法
* : 重复零次或多次
+ : 重复一次或多次
{n, m} : 重复 n 至 m 次
{n} : 重复 n 次
# * : occur 0 or more times

Beyond Joy Education – Confidential – Internal Distribution


57
print(re.search(r"ab*", "a"))
print(re.search(r"ab*", "abbbbb"))

# + : occur 1 or more times


print(re.search(r"ab+", "a"))
print(re.search(r"ab+", "abbbbb"))

# {n, m} : occur n to m times


print(re.search(r"ab{2,10}", "a"))
print(re.search(r"ab{2,10}", "abbbbb"))
10) 将找到的内容进行分组
我们还可以将找到的内容分组, 使用 () 即可实现
match = re.search(r"(\d+), Date: (.+), Name: (.+)", "Cell:123456789,
Date: 11/1/2018, Name: Python")
print(match.group())
print(match.group(1))
print(match.group(2))

# re 模块中还允许我们将分好的组进行命名,这一命名直接在 re.search 中进行


match = re.search(r"(?P<Cell>\d+), Date: (?<Date>.+), Name: (?
P<Name>.+)", "Cell:123456789, Date: 11/1/2018, Name: Python")
print(match.group('Cell'))
print(match.group('Date'))
print(match.group('Name'))

ii. 字符范围 Character Ranges


在查找字符的过程中,出于方便,我们可以搜索某一范围的字符,或剔除某一范围内的字符,具体实现如下表:

模式 解释
[0-9] 匹配任何数字
[a-z] 匹配任何小写字母
[A-Z] 匹配任何大写字母
[a-zA-Z0-
匹配任何字母及数字
9]
[^abcde] 除了 abcde 字母以外的所有字符
[^0-9] 匹配除了数字外的字符

例 5.
pattern1 = '[a-z]'
pattern2 = '[A-Z]'
pattern3 = '[A-Z][a-z]+'

Beyond Joy Education – Confidential – Internal Distribution


58
test_string = 'Bitcoin and Ethereum price continues to deflate in the past
week'

print(re.findall(pattern1,test_string))
#返回所有小写字母
['i', 't', 'c', 'o', 'i', 'n', 'a', 'n', 'd', 't', 'h', 'e', 'r', 'e', 'u', 'm', 'p', 'r', 'i', 'c', 'e',
'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', 's', 't', 'o', 'd', 'e', 'f', 'l', 'a', 't', 'e', 'i', 'n', 't', 'h', 'e',
'p', 'a', 's', 't', 'w', 'e', 'e', 'k']

print(re.findall(pattern2,test_string))
#返回所有大写字母
['B', 'E']

print(re.findall(pattern3,test_string))
#返回大写+小写(出现 1 次及以上)
['Bitcoin', 'Ethereum']
iii. Escape Codes
模式 解释
\d 匹配数字类型
\D 匹配非数字类型
\s 匹配空白字符类(空格,回车符,制表符)
\S 匹配非空白字符类
\w 匹配数字和字母及下划线
\W 匹配非数字和字母及下划线
使用反斜杠转义符时,为了使程序更有可读性,一般使用 r 符号(raw string)

例 6.
tweet='July is just the ninth month since 1970 that unemployment has
fallen below 4%. Our economy has added 3.7 million jobs since I won the
Election. 4.1 GDP. More than 4 million people have received a pay raise due
to tax reform. $400 Billion brought back from “overseas.” @FoxNews'

pattern = r'\d+'
re.findall(pattern,tweet)

pattern = r'\D+'
re.findall(pattern,tweet)

pattern = r'\s+'
re.findall(pattern,tweet)

Beyond Joy Education – Confidential – Internal Distribution


59
pattern = r'\S+'
re.findall(pattern,tweet)

pattern = r'\w+'
re.findall(pattern,tweet)

pattern = r'\W+'
re.findall(pattern,tweet)
D. 其他应用及参考
在我们公开课的时候,曾经举过几个正则表达式的例子,在系统地了解学习过正则表达式之后,我们再回头复习一下这些例子。

i. match telephone numbers


import re

def get_tel(text):
r_tel_num = re.compile(r'\d{3}-?\d{3}-?\d{4}')

match_tel_num = re.findall(r_tel_num,sample_tel)
if match_tel_num == None:
print('match failed')
else:
print('match sucess')
return match_tel_num

>>>text = 'Input 434-335-2319 to 434-335-8972, the list includes 760-994-


7483'
>>>match_tel = get_tel(text)

ii. match email address


import re

def get_email(text):
pattern = re.compile('[a-z0-9-]{1,}@[a-z0-9-]{1,}\.[a-z]{1,}')
return re.findall(pattern,text)

>>> text = '<David K> [email protected] => Kevin [email protected] =>


what?'
>>>get_email(text)

课堂练习
# 练习一
# 在世界银行的官网上,找到所有联系人的邮箱,(提示:以 mailto:开头的字符串)
import urllib.request as ur

Beyond Joy Education – Confidential – Internal Distribution


60
url='http://www.worldbank.org/en/about/contacts'

data = ur.urlopen(url).read().decode('utf-8')
pattern='mailto:.+?"'
regex = re.compile(pattern)
regex.findall(data)

# 练习二
url='http://www.slate.com'
#找出目标网页中包含的所有 url, 举例: https://twitter.com/slate" class="social__badge"

pattern = "https?://.+\..+"

data = ur.urlopen(url).read().decode('utf-8')
regex = re.compile(pattern)
regex.findall(data)

# 练习三
url='http://www.slate.com'
# 找出所有包含 article 这一单词的 url
# 举例: http://www.slate.com/articles/news_and_politics/jurisprudence/

pattern = "https?://.*article.*\..+"
data = ur.urlopen(url).read().decode('utf-8')
regex = re.compile(pattern)
regex.findall(data)

# 练习四
将加密的邮箱地址转换为可以直接被识别的邮箱地址
encoded_email = "nikkischmit112[710]beyondjoy.com; MPaul[710]goodday.net;
joanaas[710]collage.org"

email=re.sub(r'([A-Za-z0-9]*?)\[710\]([a-z]*?\.[com,org,net])' , r'\1@\
2',encoded_email)
re.findall(r'([A-Za-z0-9]+@[a-z]*\....)',email)

LESSON 10.ERROR AND EXCEPTION HANDLING


A. 什么是异常?
人无完人,我们编写的代码中总会出现一些错误,如语法错误,调用错误等。即使没有错误,当其他的程序使用者按照超出设计的方式使用了
我们的程序,异常也会因为这些不可预料的错误而出现。比如:我们设计了一个让用户输入整数,从而应用于下一步的数字运算,但用户却输

Beyond Joy Education – Confidential – Internal Distribution


61
入了一个字符。这个时候 Python 无法正常处理程序,异常就发生了。如果我们不进行异常处理,这个时候系统会报错,整段代码就会
停止运行。但若进行了异常处理,代码仍会继续运行
Python 中有两种容易辨认的错误,语法错误和异常
i. 语法错误
这是初学者经常会见到的错误,比如

if True
print('This is True')
File "<ipython-input-1-006342dbdba6>", line 1
if True
^
SyntaxError: invalid syntax
print(2*(3/5)
File "<ipython-input-2-0c93fc07b589>", line 1
print(2*(3/5)
^
SyntaxError: unexpected EOF while parsing

遇到这种错误,只需要找到^标记处 的语句,更正语法错误即可,当然,我们要尽量避免犯这类错误。

除了这种人为的错误之外,还有另外一种,语法上正确,但是在运行时仍然出错的语句,这种语句被称为异常。大多数异常都会直接中断程序
并返回相应的错误信息。
print(2*(3/5)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-f4e83b2e787b> in <module>()
----> 1 print(a*3)

NameError: name 'a' is not defined


c = 1+5/0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-4-ee53b86d0d1d> in <module>()
----> 1 c = 1+5/0

ZeroDivisionError: division by zero

为了让程序学会处理异常而不是一味地跳出程序运行,我们就要对异常进行处理。

B. 如何处理异常?
我们通常使用 try/except 语句来处理程序执行过程中出现的异常。
基本格式为:
try:
执行语句(可能引发异常的操作)
except:
执行语句(如果异常出现则进行的操作)

Beyond Joy Education – Confidential – Internal Distribution


62
语句执行的顺序如下:

try 语句按照如下方式工作;
(1)执行 try 子句(在关键字 try 和关键字 except 之间的语句)
(2)若没有异常发生,忽略 except 子句,try 子句执行后结束。
(3)若在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的错误名符合,
则对应的 except 后的代码块将被执行。最后执行 try 语句之后的代码。
(4)如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。系统依然会报错。
注意:
 一个 try 语句可能包含多个 except 子句,分别来处理不同的特定的异常。最多只有一个分支会被执行。
 处理程序将只针对对应的 try 子句中的异常进行处理,而不是其他的 try 的处理程序中的异常。
 一个 except 子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,如
except(TypeError, NameError)

例 1.
result = 20 + '10'
TypeError Traceback (most recent call last)
<ipython-input-3-78075317c276> in <module>()
----> 1 result = 20 + '10'
TypeError: unsupported operand type(s) for +: 'int' and 'str'
因为 int 和 str 不是一个数据类型无法加减,系统报错了,整个程序停止进行。我们现在来试一下使用 try/except:
try:
result = 20 + '10'
except:
print('You are not adding correctly.')
此时系统输出的结果是 You are not adding correctly. 并且没有停止整个程序。
现在我们在此例中加入 else 语句,else 语句里是如果没有发生异常而执行的语句。
try:
result = 20 + 10
except:
print('You are not adding correctly.')
else:
print(‘Everything went well.’)
print(result)
因为此时我们 try 中的执行语句没有异常,所以系统执行 else 中的语句,即 Everything went well. 30。
在上例中,我们并没有用 except 子句来捕获特定异常,即所有的异常都会以相同的方式被处理。从上例之前的报错我们可以看到,错
误类型为 TypeError(对类型无效的操作)。常见的错误类型除此之外,还有 ValueError(传入无效的参数),
ZeroDivisionError(除零), SyntaxError(语法错误), OSError()等等。我们可以通过 except 子
句来捕获不同的异常,并用不同的方式来处理。

例 2.
try:
newfile = open('newfile', ’w’)

Beyond Joy Education – Confidential – Internal Distribution


63
newfile.write('Write a new line')
except TypeError:
print('There was a type error.')
except OSError:
print('You have an OS error.')
finally:
print(‘Always run.’)
#Always run.
为了测试结果,我们讲 try 中 newfile = open('newfile', ’w’)改为 newfile =
open('newfile'),即没有写权。
#You have an OS error.
#Always run.
我们可以看到在这个例子中加入了 finally 语句,而且无论是否有异常,也无论有什么样的异常,其中语句都会执行。
至此,我们学习了 try, except, else 和 finally,下面用一个例子来应用一下。
def enter_id_number():
while True:
try:
result = int(input('Please enter your id number: '))
except:
print('Sorry, that is not a valid number')
continue
else:
print('Ok, got it!')
break
finally:
print('End of try/except/finally. Always run.')
执行函数 enter_id_number(),输入数字 12,得出结果为:
Please enter your id number: 12
Ok, got it!
End of try/except/finally. Always run.

执行函数 enter_id_number(),输入’word’,得出结果为:
Please enter your id number: word
Sorry, that is not a valid number
End of try/except/finally. Always run.
Please enter your id number:
程序会一直运行直到你输入了数字。而结果中打印了’Sorry, that is not a valid number’正是因为我们的异常处理
起到了作用。

LESSON 11. 函数的高级特性


A. 装饰器 decorator

Beyond Joy Education – Confidential – Internal Distribution


64
装饰器的用途 – 在不影响主要函数本身的代码和功能的条件下,给函数增加额外的功能,从而省去了更改函数内代码的麻烦。有了装饰器,我
们就可以抽离出大量与函数功能本身无关的雷同代码并重复使用。
简单的例子如下

def weekday():
print('It is Sunday today.')
如果我们想要在函数运行的时候进行一下记录,我们可以再函数本身当中加一行 print 代码,使函数本身执行的时候执行,但是,如果我们
有许多个类似的函数,我们都想进行运行记录,那一行一行地添加不但浪费时间,还有可能造成一些不必要的 bug
这个时候装饰器就起到了作用
def log(func):
def wrapper(*args,**kwargs):
print('{}().'.format(func.__name__))
return func(*args,**kwargs)
return wrapper

@log
def weekday():
print('It is Sunday today.')

@log
def now():
print('2018-11-04')
我们看到的函数 log 就是一个装饰器,他本身是一个函数。他的作用是将真正执行业务的 func 包裹在其中,就像把 func 装饰起来了
一样,故称作装饰器。而且我们可以看到,同一个装饰器可以轻松实现对不同函数的装饰,节省了大量时间精力。

装饰器作为一个函数,它本身也可以接受输入参数,这就更为复杂一些。我们需要再写一层 decorator(func)
def log(name):
def decorator(func):
def wrapper(*args,**kwargs):
print('{} is calling {}().'.format(name, func.__name__))
return func(*args,**kwargs)
return wrapper
return decorator

@log('Student')
def weekday():
print('It is Sunday today.')
此时的 log 就是一个含有输入参数的装饰器,它其实是对原有装饰器(decorator)的另一层函数封装,他的返回值是装饰器。

B. 列表生成 list comprehensions

Beyond Joy Education – Confidential – Internal Distribution


65
如果我们想要生成一个 list[1,2,3,4,5,6,7,8,9,10]按照我们之前学过的, 可以进行操作
list(range(1,11))
但是如果我们想要生成计算 list 中每个数的平方并返回一个平方序列呢?
当然我们可以通过循环来实现,但是有没有更加简单,更加 python 的方式呢?
答案是有的, 就是 list comprehensions
squared_list = [ x*x for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
从上面的例子可以看出基本格式
[ 要生成的元素 for 循环变量 in …]
有时候我们还需要在循环中加入判断语句来筛选需要循环的变量,这也是允许的,比如如果我们只需要计算奇数的平方:
>>>[x*x for x in range(1,11) if x % 2 != 0]
[1, 9, 25, 49, 81]
list comprehensions 还可以应用于两个甚至多个循环变量
>>>d = {'a':1,'b':2,'c':3}
>>>['The square of ' + k + ' is ' + str(v**2) for k,v in d.items()]
['The square of a is 1', 'The square of b is 4', 'The square of c is 9']

Test 1: 使用 lower()函数将下面这个 list 中的所有字母变成小写。


L = ['Learing', 'PYTHON', 'iS', 'So','ExciTING']

Test 2: 使用 isinstance()函数和 lower()函数,将以下 list 中所有字母变成小写


L = ['WE', 'HAVE', 2, 'classES','EACH','WEEK']
C. 生成器 generator
列表容量是有限的。创建一个包含 100 万个元素的列表会占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元
素占用的空间都白白浪费了。因此我们想问的是,如果生成的每一个列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不
断推算出后续的元素呢而不是创建完整的 list 呢。在 Python 中,这种一边循环一边计算的机制就是 generator
要创建一个 generator,有很多种方法。最简单的方法是把一个列表生成式的[]改成()即可
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
#写成()形式
>>> g = (x * x for x in range(10))
定义好 generator 之后,在 g 中我们就储存了一个算法,每次调用 g 的时候系统就会计算下一个算法返回的值,我们可以通过
next()函数一个个地向下访问 g 生成的元素
next(g)
通常我们都会使用 for 循环来返回每一个 generator 的返回对象
for i in g:
print(i)
另一种定义 generator 的方法是 yield,如果一个函数的定义中包含了 yield 关键字,那么这个函数就不是一个普通函数,而
是变成了一个 generator.
def firstnum(n):
num = 0

Beyond Joy Education – Confidential – Internal Distribution


66
while num < n:
yield num
num += 1

>>> sum_of_first_num = sum(firstnum(100))


>>> sum_of_first_num
4950
可以看出,这个 generator 按照顺序返回从 0 开始的数字,而 sum 则对所有数字进行了加和。
再举个例子,定义一个生成器,依次返回数字 1,3,5
def odd():
print('print 1')
yield 1
print('print 3')
yield(3)
print('print 5')
yield(5)

>>>o = odd()
>>>next(o)
print 1
1
>>>next(o)
print 3
3
>>>next(o)
print 5
5
可以看出的是,odd 作为一个 generator,在执行过程中遇到 yield 会中断,在下次调用 next 时继续执行,如果我们在三
步之后还调用 next,系统就会报错了,因为并不存在下面的结果。
下面举一个稍微复杂一些的例子,使用生成器来每次选取给定的数字中最大值
def counter(maximum):
i=0
while i < maximum:
val = (yield i)
# If value provided, change counter
if val is not None:
i = val
else:
i += 1

>>> it = counter(10)
>>> next(it)
0
Beyond Joy Education – Confidential – Internal Distribution
67
>>> next(it)
1
>>> it.send(8)
8
>>> next(it)
9

可以看出,由于 yield 命令并没有返回值,所以我们需要用 send()函数来给 it 赋值


D. Enumerate

enumerate(iterable, start=0)
enumerate 列举器,也是 python 中很独特的一个内置函数特性。它的作用是给循环变量添加一个 counter,这样我们在使用
python 特有的循环方式——遍历某个 list 或者 string 中的元素的时候,就不会发愁没有相对应的 index 来引用。下面我们来看
一下这个函数的作用

names = ['Adam', 'Bill', 'Charles','David']


enumeratenames= enumerate(names)

print(type(enumeratenames))

# 转换成 list
print(list(enumeratenames))

# 给 counter 赋值取代默认的 0
enumeratenames = enumerate(names, 10)
print(list(enumeratenames))8
学会了这一写法之后,我们可以将这一特性加以应用。比如给学生添加学号
names = ['Adam', 'Bill', 'Charles','David']

for item in enumerate(names):


print(item)

for count, name in enumerate(names):


print(count, name)

for count, name in enumerate(names, 2000):


print('The ID number for {1} is {0}.'.format(count, name))

Beyond Joy Education – Confidential – Internal Distribution


68
LESSON 12. 面向对象程序设计初步
A. 面向对象编程(Object Oriented Programming – OOP)
OOP 是一种程序设计思想。OOP 把对象作为程序的基本单元,一个对象包含了数据和相应的对数据进行操作的的函数(此处称为方法)。
面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即
把大块函数分割成若干小块函数从而降低系统复杂度。
在 Python 中,所有数据类型都可以视为对象,而用户自定义的对象数据类型就是面向对象中的类(Class)。
B. 举例我们可以将学生设置为一类,在类中包含一些信息和方法

class StudentGrade:
"""
Here is the doc for this class
"""
def __init__(self, name, score):
self.name = name
self.score = 0

def print_score(self):
print('Name: {}, Score: {}'.format(self.name,self.score))

def add_to_score(self, new_score):


self.score = self.score + new_score

在自定义的类中,我们可以定义一些特殊的 property
class StudentGrade:

def __init__(self, name):


self.name = name
self.__score = 0

@property
def score(self):
return self.__score
@score.setter
def score(self,score):
if score > 100:
self.__score = 100
elif score <0:
self.__score = 0
else:
self.__score = score

Beyond Joy Education – Confidential – Internal Distribution


69
设定 class 层级上的方法
class StudentGrades(object):
number_of_students = 0

def __init__(self,name):
self.name = name
self.score = 0
StudentGrades.increase_students()

@property
def score(self):
return self.__score

@score.setter
def score(self,score):
if score > 100:
self.__score = 100
elif score <0:
self.__score = 0
else:
self.__score = score

@classmethod
def increase_students(cls):
cls.number_of_students=cls.number_of_students + 1
Python 还允许我们自定义一些特殊的方法,对系统自带的类型进行更多的操作。
class SpecialString:
def __init__(self,v):
self.value=v

def __eq__(self,other):
if len(self.value) == len(other.value):
return True
else:
return False
def __lt__(self,other):
if len(self.value) < len(other.value):
return True
else:
return False
下面我们进行一个练习,建立一个 account 类,包含账户名,余额,并加入基本的存取方法
class BankAccount:

Beyond Joy Education – Confidential – Internal Distribution


70
def __init__(self):
self.balance = 0

def withdraw(self, amount):


self.balance -= amount
return self.balance

def deposit(self, amount):


self.balance += amount
return self.balance
类的继承特性:
大类 – 动物
小类 – 狗,猫,兔 (继承了动物类的特性,同时有自身独特的特性)
练习一 – 写一个 Animal 大类和三种不同的动物小类

class MinimumBalanceAccount(BankAccount):
def __init__(self, minimum_balance):
BankAccount.__init__(self)
self.minimum_balance = minimum_balance

def withdraw(self, amount):


if self.balance - amount < self.minimum_balance:
print 'Sorry, minimum balance must be maintained.'
else:
BankAccount.withdraw(self, amount)
练习二 - 给前面写的 Account 类加一个最低限额的小类
class MinimumBalanceAccount(BankAccount):
def __init__(self, minimum_balance):
BankAccount.__init__(self)
self.minimum_balance = minimum_balance

def withdraw(self, amount):


if self.balance - amount < self.minimum_balance:
print 'Sorry, minimum balance must be maintained.'
else:
BankAccount.withdraw(self, amount)

类的多态性:
对于同一个大类下的不同小类,我们在定义和调用函数的时候不需要知道小类具体是什么,只需要知道其归属的大类即可,这就是多态的特性。

def food(Animal):

Beyond Joy Education – Confidential – Internal Distribution


71
Animal.get_food()
food(Dog())

Beyond Joy Education – Confidential – Internal Distribution


72

You might also like