Python Class
Python Class
Python 的不可替代性更强,是一种必要的数据分析语言。
在资深数据分析人员的推荐当中,Python 也远胜另一种流行的语言 R。
那么学 python,用什么平台,怎么学,我们也要有针对性,下面这张图足以说明一切。可以看出,大部分 data 从业者都很常用
jupyter notebook 和 SQL,这也是我们这门课的平台和重点。
查看当前工作的目录,更改当前工作的目录
查看当前工作目录 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
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"}
例 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
例 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'>
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
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” – 不能使
用有特定含义的词
例 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"')
例 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()所不具备的。
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 次分割
例 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)
课堂练习:写一行代码,向用户请求输入一个数字,无论用户输入的是整数还是浮点数,程序都输出该数字的整数部分。
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
可以直接输出数字,字符,数字的计算结果等。
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
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. 读取
有几种不同的读取方式
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)
>>>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]
>>>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]
>>>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)
>>>print(mylist)
[13, 8, 2, 9, 4, 1, 6, 3]
viii. list.count()
对 list 中的成员进行计数
list1 = [123, 'xyz', 'ddd', 'abc', 123]
>>>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 中的元素添加进来
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)
>>>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)
S1.union(s2)将两个集合 union 起来
Input: [1,2,3,4]
Output: false
Input: [1,1,1,3,3,4,3,2,4,2]
Output: true
>>>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)
在学习了这些数据和变量类型之后,我们再来看一看常见的类型转换函数,我们已经学习了这其中的大部分内容,其他的函数用法也很相似。
函数 作用
float(x) 将 x 转换到一个浮点数
set(s) 转换为可变集合
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串
运算符 描述
== 等于 - 比较对象是否相等
!= 不等于 - 比较两个对象是否不相等
> 大于 - 返回 x 是否大于 y
#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 语句的执行如下图:
例 1. 循环输出变量 i 的值
for i in range(0,10):
print('i is',i,'now')
Python 中 For loop 的特性,可以直接遍历成员,并不必须使用 index
例 4.
d = {‘x1’:15,’x2’:10,’x3’:22}
for item in d:
print(item)
x1
x2
x3
例 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,
Example 1:
Input: [7,1,5,3,6,4]
Output: 5
含义:在第二天的时候以 1 的价格买进,在第五天的时候以 6 的价格卖出,可以获得这一时间段上的最大利润 5
Input: [7,6,5,3,2,1]
Output: 0
此时,不存在盈利的可能性,返回 0
思考:其他代码不变,如果数字初始值为 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
例 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
作用 – ?
先来看一个例子
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
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)
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)
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 表达式如下:
>>>randrange(1,10,2)
>>>choice([1,2,3,4,5])
>>> choice('abcdefg')
for i in range(15):
print(fibonacci(i),end = ' ')
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
例 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
例 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。
例 7. 将时间字符串转换为 datetime 对象
例 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)
# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]])
bool_idx = (a > 2)
print(bool_idx)
print(a[bool_idx])
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]])
# 求平均
print(np.mean(x))
#求 sin,cos
print(np.sin(x))
print(np.cos(x))
#对矩阵求转置
print(x.T)
D. Python 中的 pandas 模块
Pandas 是基于 numpy 所构建的,为时间序列分析,矩阵分析,数据可视化提供更好支持的模块,包含两种数据结构,
Series 与 DataFrame
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
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'])
df.head()
df.tail(3)
df.index
df.columns
df.values
df.describe()
df.sort_index(axis=1, ascending=False)
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]
df.mean(1)
df.apply(np.cumsum)
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2018',
periods=1000))
ts = ts.cumsum()
ts.plot()
plt.figure()
df.plot()
plt.legend(loc='best')
掌握了这些之后,我们就可以进行一些简单的数据分析了
pattern1 = "cat"
pattern2 = "bird"
string = "dog runs to cat"
print(pattern1 in string) # True
print(pattern2 in string) # False
# regular expression
pattern1 = "cat"
pattern2 = "bird"
string = "dog runs to cat"
print(re.search(pattern1, string))
print(re.search(pattern2, string))
例 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
['@', '@', '@', '@', '@']
pattern = 'M[a-z]+'
regex = re.compile(pattern)
regex.findall(test_string)
例 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. 正则表达式模式:
模式字符串使用特殊的语法来表示一个正则表达式,通过编写一个正则表达式模式,我们可以方便地查找并匹配到想要的模式字符,在正则表
达式模式中
例 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']
模式 解释
[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]+'
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)
pattern = r'\w+'
re.findall(pattern,tweet)
pattern = r'\W+'
re.findall(pattern,tweet)
D. 其他应用及参考
在我们公开课的时候,曾经举过几个正则表达式的例子,在系统地了解学习过正则表达式之后,我们再回头复习一下这些例子。
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
def get_email(text):
pattern = re.compile('[a-z0-9-]{1,}@[a-z0-9-]{1,}\.[a-z]{1,}')
return re.findall(pattern,text)
课堂练习
# 练习一
# 在世界银行的官网上,找到所有联系人的邮箱,(提示:以 mailto:开头的字符串)
import urllib.request as ur
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)
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)
为了让程序学会处理异常而不是一味地跳出程序运行,我们就要对异常进行处理。
B. 如何处理异常?
我们通常使用 try/except 语句来处理程序执行过程中出现的异常。
基本格式为:
try:
执行语句(可能引发异常的操作)
except:
执行语句(如果异常出现则进行的操作)
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’)
执行函数 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’正是因为我们的异常处理
起到了作用。
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)的另一层函数封装,他的返回值是装饰器。
>>>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
enumerate(iterable, start=0)
enumerate 列举器,也是 python 中很独特的一个内置函数特性。它的作用是给循环变量添加一个 counter,这样我们在使用
python 特有的循环方式——遍历某个 list 或者 string 中的元素的时候,就不会发愁没有相对应的 index 来引用。下面我们来看
一下这个函数的作用
print(type(enumeratenames))
# 转换成 list
print(list(enumeratenames))
# 给 counter 赋值取代默认的 0
enumeratenames = enumerate(names, 10)
print(list(enumeratenames))8
学会了这一写法之后,我们可以将这一特性加以应用。比如给学生添加学号
names = ['Adam', 'Bill', 'Charles','David']
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))
在自定义的类中,我们可以定义一些特殊的 property
class StudentGrade:
@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
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:
class MinimumBalanceAccount(BankAccount):
def __init__(self, minimum_balance):
BankAccount.__init__(self)
self.minimum_balance = minimum_balance
类的多态性:
对于同一个大类下的不同小类,我们在定义和调用函数的时候不需要知道小类具体是什么,只需要知道其归属的大类即可,这就是多态的特性。
def food(Animal):