Task 4–函数
一、什么是函数
1.1函数的作用
•它们为一些代码起名字,就像变量为字符串和数字起名字一样。
•它们像脚本获取 argv 一样获取参数(arguments)。
•通过前面的操作,让你做一些你自己的“小脚本”或者“微命令”。
下面通过在 Python 中使用 def 来创建一个函数。会创建 4 个不同的函数,它们就像脚本一样运行:
#this one is like your scripts with argv
def print_two(*args):
arg1,arg2 = args
print(f"arg1:{arg1},arg2:{arg2}")
#ok,that *args is actually pointless,we can just do this
def print_two_again(arg1,arg2):
print(f"arg1:{arg1},arg2:{arg2}")
#this just takes one argument
def print_one(arg1):
print(f"arg1:{arg1}")
#this one takes no argument
def print_none():
print("I got nothing.")
print_two("Zed","Shaw")
print_two_again("Zed","Shaw")
print_one("First!")
print_none()
arg1:Zed,arg2:Shaw
arg1:Zed,arg2:Shaw
arg1:First!
I got nothing.
从中我们可以得到结论:
1、 Python 用 def (即 define)来创建一个函数。
2、在 def 的同一行我们给了函数一个名字,本例中是 print_two,名字没关系,不过最好简短一些,并且能够说明这个函数的作用。
3、函数的参数要放在()里,本例中,是*args ,它很像参数 args ,只不过是为函数设的,必须放在括号里面才能工作。
4、以冒号 结束这一行,另起一行开始缩进。
5、在冒号之后缩进四个空格的所有行都是关于 print_two 这个函数名的。第一个缩进的行就是用来解包这个参数(argument),跟之前的脚本一样。
1.2附加练习
创建一个如下的函数 checklist (核查表)用于后面的练习。把这些内容写在索引卡上,一直保留到你完成所有剩余练习的时候或者当你感觉你不再需要这些索引卡的时候:
def checklist1():
print("你是否用 def 来创建函数了?")
print("你的函数名是只包含字符和 _ (下划线)吗?")
print("你在函数名后面放 ( (左圆括号)了吗?")
print("你在左圆括号后面放参数(argument)了吗?参数之间是以逗号")
print("你的每个参数都是唯一的吗(即没有重名)?")
print("你在参数后面放 ) (右圆括号)和 : (冒号)了吗?")
print("你在与这个函数相关的代码行前面加上四个空格的缩进了吗?(不能多,也不能少)")
print("你是通过另起一行不缩进来结束你的函数的吗?")
def checklist2():
print("你是通过输入函数名称来运行/调用/使用一个函数的吗?")
print("你运行的时候有在名称后面加 ( 吗?")
print("你有把你想要的值放在圆括号里并用逗号隔开了吗?")
print("你是以 ) 来结束调用这个函数的吗?")
checklist1()#调用checklist1函数
checklist2()#调用checklist2函数
def checklist():
checklist1()
checklist2()
checklist()#调用checklist函数
你是否用 def 来创建函数了?
你的函数名是只包含字符和 _ (下划线)吗?
你在函数名后面放 ( (左圆括号)了吗?
你在左圆括号后面放参数(argument)了吗?参数之间是以逗号
你的每个参数都是唯一的吗(即没有重名)?
你在参数后面放 ) (右圆括号)和 : (冒号)了吗?
你在与这个函数相关的代码行前面加上四个空格的缩进了吗?(不能多,也不能少)
你是通过另起一行不缩进来结束你的函数的吗?
你是通过输入函数名称来运行/调用/使用一个函数的吗?
你运行的时候有在名称后面加 ( 吗?
你有把你想要的值放在圆括号里并用逗号隔开了吗?
你是以 ) 来结束调用这个函数的吗?
你是否用 def 来创建函数了?
你的函数名是只包含字符和 _ (下划线)吗?
你在函数名后面放 ( (左圆括号)了吗?
你在左圆括号后面放参数(argument)了吗?参数之间是以逗号
你的每个参数都是唯一的吗(即没有重名)?
你在参数后面放 ) (右圆括号)和 : (冒号)了吗?
你在与这个函数相关的代码行前面加上四个空格的缩进了吗?(不能多,也不能少)
你是通过另起一行不缩进来结束你的函数的吗?
你是通过输入函数名称来运行/调用/使用一个函数的吗?
你运行的时候有在名称后面加 ( 吗?
你有把你想要的值放在圆括号里并用逗号隔开了吗?
你是以 ) 来结束调用这个函数的吗?
1.3常见问题
•函数名称有哪些要求?
跟变量名一样,任何不以数字开头的字母、数字、下划线组合都可以。
•*args 中的 * 是什么作用?
这是告诉 Python 取所有的参数给函数,然后把它们放在 args 里放成一列,很像你之前学的 argv ,只不过这个是为函数设置的。这种不常用,除非有特殊需要。
二、函数和变量
2.1通过练习认识函数与变量
def cheese_and_crackers(cheese_count,boxes_of_crackers):
print(f"You have {cheese_count} cheeses!")
print(f"You have {boxes_of_crackers} boxs of crackers!")
print("Man that's enough for a party!")
print("Get a blanket.\n")
print("We can just give the function numbers directly:")
cheese_and_crackers(20,30)
print("OR,we can use variables from our script:")
amount_of_cheese = 10
amount_of_crackers = 50
cheese_and_crackers(amount_of_cheese,amount_of_crackers)
print("We can even do math inside too:")
cheese_and_crackers(10+20,5+6)
print("And we can combine the two,variables and math:")
cheese_and_crackers(amount_of_cheese + 100,amount_of_crackers +1000)
We can just give the function numbers directly:
You have 20 cheeses!
You have 30 boxs of crackers!
Man that's enough for a party!
Get a blanket.
OR,we can use variables from our script:
You have 10 cheeses!
You have 50 boxs of crackers!
Man that's enough for a party!
Get a blanket.
We can even do math inside too:
You have 30 cheeses!
You have 11 boxs of crackers!
Man that's enough for a party!
Get a blanket.
And we can combine the two,variables and math:
You have 110 cheeses!
You have 1050 boxs of crackers!
Man that's enough for a party!
Get a blanket.
这个练习展示了我们可以给函数 cheese_and_crackers 赋值的几种不同的方式,我们可以直接给它数字,或者变量,亦或是数学运算,甚至是数学运算和变量的结合。
从某种程度上说,函数的参数有点类似于我们给变量赋值时的 = 符号 。事实上,如果你可以用 = 来定义一个东西,你就可以把它作为参数赋给函数。
2.2 附加练习
•回顾一遍这个脚本,然后在每一行上方加上注释,解释它的作用。
def cheese_and_crackers(cheese_count,boxes_of_crackers):
#定义名为 cheese_and_crackers 的函数
print(f"You have {cheese_count} cheeses!")
print(f"You have {boxes_of_crackers} boxs of crackers!")
print("Man that's enough for a party!")
print("Get a blanket.\n")
print("We can just give the function numbers directly:")
cheese_and_crackers(20,30)#用直接给数字的方法给函数赋值
print("OR,we can use variables from our script:")
amount_of_cheese = 10
amount_of_crackers = 50
cheese_and_crackers(amount_of_cheese,amount_of_crackers)#用给变量的方法为函数赋值
print("We can even do math inside too:")
cheese_and_crackers(10+20,5+6)#用数学运算的方法给函数赋值
print("And we can combine the two,variables and math:")
cheese_and_crackers(amount_of_cheese + 100,amount_of_crackers + 1000)#用数学运算和变量结合的方法给函数赋值
•从下到上阅读每一行,说出所有重要的字符。
(1)def cheese_and_crackers:定义名为cheese_and_crackers的函数
(2)括号中的cheese_count,boxes_of_crackers:函数的参数
•写至少一个自己设计的函数,然后用 10 种不同的方式运行它。
def sum3Number(a,b,c):# 定义函数求3个数的和
return a+b+c # return 的后面可以是数值,也可是一个表达式
sum3Number(2,3,4)#用直接给数字的方法给函数赋值
num1 = 1
num2 = 2
num3 = 3
sum3Number(num1,num2,num3)#用给变量的方法赋值
sum3Number(1 + 1,2 + 2,100+10)#用数学运算的方法
sum3Number(1 + num1,1 + num2,1+num3)#变量加数学运算的方法
2.3常见问题
详见教程https://linklearner.com/datawhale-homepage/index.html#/learn/detail/6
三、函数和文件
3.1认识函数与文件
input_file = 'test.txt'
def print_all(f):
print(f.read())
def rewind(f):
f.seek(0)
def print_a_line(line_count,f):
print(line_count,f.readline())
current_file = open(input_file,encoding='Utf-8')
#print(current_file)
print("First let's print the whole file:\n")
print_all(current_file)
print("Now let's rewind,kind of like a tape.")
rewind(current_file)
print("Let's print three lines:")
current_line = 1
print_a_line(current_line,current_file)
current_line =current_line + 1
print_a_line(current_line,current_file)
current_line =current_line + 1
print_a_line(current_line,current_file)
First let's print the whole file:
This is line 1
This is line 2
This is line 3
Now let's rewind, kind of like a tape.
Let's print three lines:
1 This is line 1
2 This is line 2
3 This is line 3
3.2附加练习
•在代码每一行添加注释解释它的作用。
input_file = 'test.txt'#文件名称
def print_all(f):#定义print_all()函数
print(f.read())#函数作用是读取文件
def rewind(f):#定义rewind()函数
f.seek(0)#函数作用是将文件移到首字符位置
def print_a_line(line_count,f):#定义print_a_line()函数
print(line_count,f.readline())#作用是输出一行中的字符
current_file = open(input_file,encoding='Utf-8')#打开文件
#print(current_file)
print("First let's print the whole file:\n")
print_all(current_file)#调用print_all()函数
print("Now let's rewind,kind of like a tape.")
rewind(current_file)#调用rewind()函数
print("Let's print three lines:")
current_line = 1
print_a_line(current_line,current_file)#函数 readline() 返回一行以 \n 结尾的文件内容, 在你调用print函数的最后增加一个逗号',',用来避免为每一行添加两个换行符 \n
current_line =current_line + 1
print_a_line(current_line,current_file)
current_line =current_line + 1
print_a_line(current_line,current_file)
•每次 print_a_line 运行的时候,你都在传入一个 current_line 变量。写出每一次调用函数的时候 current_line 等于什么,然后找出它是如何变成print_a_line 里面的 line_count 的。
我认为current_line的具体数值跟line_count没有关系,按行输出是依靠readline()函数只读取一行的性质。根据这一性质,将current_line的初始值设为1,然后令其每运行一次递增1,使其与line_count相匹配。
若将初始值改成别的值,就会出现不匹配的现象如下
PS D:\pythonp> python ex20.py test20.txt
First let's print the whole file:
This is line 1.
This is line 2.
This is line 3.
Now let's rewind, kind of like a tape.
Let's print three lines:
2 This is line 1.
3 This is line 2.
4 This is line 3.
若把每次+1去掉,则会出现下列情况
First let's print the whole file:
This is line 1.
This is line 2.
This is line 3.
Now let's rewind, kind of like a tape.
Let's print three lines:
1 This is line 1.
1 This is line 2.
1 This is line 3.
出现重复。
•找出每一个用到函数的地方,然后检查它的 def 确保你给出了正确的参数。
•在网上搜搜 seek 这个函数的作用。试着输入 pydoc file,看看你能否从这里看明白。然后试着输入 pydoc file.seek 再看看 seek 是用来干嘛的。
(1)用法
seek() 方法用于移动文件读取指针到指定位置。
(2)语法
seek() 方法语法如下:
fileObject.seek(offset[, whence])
(3)参数
·offset – 开始的偏移量,也就是代表需要移动偏移的字节数
·whence:可选,默认值为 0。给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。
(4)返回值
如果操作成功,则返回新的文件位置,如果操作失败,则函数返回 -1。
参考菜鸟教程https://www.runoob.com/python/file-seek.html
•搜一下简化符号 += ,然后用 += 重新写这个脚本。
x += y 等同于 x = x + y
四、函数可以返回一些东西
4.1 认识一个新的 python 字符 return
练习
def add(a,b):
print(f"Adding {a} + {b}")
return a+b
def subtract(a,b):
print(f"Subtracting {a} - {b}")
return a - b
def multiply(a, b):
print(f"MULTIPLYING {a} * {b}")
return a * b
def divide(a, b):
print(f"DIVIDING {a} / {b}")
return a / b
print("Let's do some math with just functions!")
age = add(30, 5)
height = subtract(78, 4)
weight = multiply(90, 2)
iq = divide(100, 2)
print(f"Age: {age}, Height: {height}, Weight: {weight}, IQ: {iq}")
# A puzzle for the extra credit, type it in anyway.
print("Here is a puzzle.")
what = add(age, subtract(height, multiply(weight, divide(iq, 2))))
print("That becomes: ", what, "Can you do it by hand?")
Let's do some math with just functions!
Adding 30 + 5
Subtracting 78 - 4
MULTIPLYING 90 * 2
DIVIDING 100 / 2
Age: 35, Height: 74, Weight: 180, IQ: 50.0
Here is a puzzle.
DIVIDING 50.0 / 2
MULTIPLYING 180 * 25.0
Subtracting 74 - 4500.0
Adding 35 + -4426.0
That becomes: -4391.0 Can you do it by hand?
4.2附加练习
•如果你还不能真正理解 return 是干什么的,试着写几个你自己的函数,并且让它们返回一些值。你可以让它 return 任何东西,只要你把它们放在 = 右边即可。
•脚本的最后是一个难题。我在用一个函数的返回值作为另一个函数的参数,这是在一个链(chain)里面进行的,这样就用函数创建了一个公式。它看起来确实很难,但是如果你运行这个脚本,你就可以看到结果。你要做的就是试着弄明白创建同样操作的平常的函数是什么样的。
what1 = divide(iq, 2)
what2 = multiply(weight, what1)
what3 = subtract(height, what2)
what_one = add(age, what3)
print(what_one)
DIVIDING 50.0 / 2
MULTIPLYING 180 * 25.0
SUBTRACTING 74 - 4500.0
ADDING 35 + -4426.0
-4391.0
•一旦你有了可以解出这个难题的公式,试着对函数的某些部分做做改动,看看会发生什么。有意改动一些数让它产生一些不同的值。
what1 = divide(iq, 2)
# 此处令传递给multiply的第一个参数变为weight+5
what2 = multiply(weight + 5, what1)
what3 = subtract(height, what2)
what_one = add(age, what3)
print(what_one)
DIVIDING 50.0 / 2
# 可以看到此处第一个参数由180变为185,后面的值也因此改变
MULTIPLYING 185 * 25.0
SUBTRACTING 74 + 4625.0
ADDING 35 + -4551.0
-4516.0
•做相反的操作。写一个简单的公式,然后用同一种方式通过函数来计算它。
# (a-b)*{b+(c/d)}
# 定义add函数,输出提示性字符串并返回两变量相加所得的值
def add(a, b):
print(f"ADDING {a} + {b}")
return a + b
# 定义subtract函数:输出提示性字符串并返回两变量相减所得的值
def subtract(a, b):
print(f"SUBTRACTING {a} - {b}")
return a - b
# 定义multiply函数:输出提示性字符串并返回两变量相乘所得的值
def multiply(a, b):
print(f"multiply {a} - {b}")
return a - b
# 定义divide函数:输出给定的两个参数值相除得到的结果
def divide(a, b):
print(f"DIVIDING {a} / {b}")
return a / b
def function(a,b,c,d):
c = multiply(subtract(a, b),add(b,divide(c,d)))
return c
function(200,50,30,70)
输出结果
SUBTRACTING 200 - 50
DIVIDING 30 / 70
ADDING 50 + 0.42857142857142855
multiply 150 - 50.42857142857143
99.57142857142857
4.3return总结
•return是函数传回值的一个基本方式
•return 语句就是将结果返回到调用的地方,并把程序的控制权一起返回
•程序运行到所遇到的第一个return即返回(退出def块),不会再运行第二个return
•退出函数,选择性地向调用方返回一个表达式
•不带参数值的return语句返回None
五、拓展与总结
5.1一些拓展知识
1、函数的参数
函数的参数分为形参和实参,
顾名思义,一个形式上的参数,一个实实在在的参数。
•形参的角度分类:
(1)位置参数, 按照顺序 ,一 一对应。
(2)默认参数,如果你给我一个值,我会将原来默认的参数覆盖掉。如果你不给我传值,就是设置好的默认参数。默认参数可以简化函数的调用。
(3) 万能参数,也叫动态参数,*args ,**kwargs
(4) 形参的顺序 :位置参数,*args,默认参数,**kwargs。
•注意
(1)位置参数是最大的,一定要摆在第一位,实参中的也一样,如果摆在后面肯定报错,要么少了,要么多了
(2) args实际上也是位置参数,就是实参中在形参中的args的位置有多少个参数,那就吃多少个参数。
(3)如果把默认参数摆在他两前,都被args给吸走了。
(4)**kwargs一定是在最后的。实质上是一个默认参数
(5)传参陷阱:如果默认参数是一个可变的数据类型,那么他的内存地址用的是一个。
参考链接:https://blog.csdn.net/weixin_42233629/article/details/81805840
2、一个函数中可以有多个return语句,但是只要有一个return语句被执行到,那么这个函数就会结束了,因此后面的return没有什么用处。
3、return后面可以是元组,列表、字典等,只要是能够存储多个数据的类型,就可以一次性返回多个数据,以逗号分隔 。
4、函数里的 f 是什么东西? f 是一个变量,就像你在练习 18 中函数的变量一样,只不过这次它是一个文件。文件在 Python 里面有点类似于一个老式电脑里面的磁带驱动器,或者一个 DVD 播放机。它有一个“读取头”(read head),你可以在文件里 seek (寻找)这个读取头所在的位置,然后在那里工作。每次你做 f.seek(0) 的时候你都会从移动到文件最开始,每次你做 f.readline() 的时候,你都在从文件里读取一行内容,并且把读取头移动到 \n 后面,也就是每行结束的地方。
5.2总结
Task 4主要对函数的相关概念进行了梳理,这一部分之前并没有系统的学习过,所以有很多相关概念不大清楚。中间也有一些不扎实的知识点和还要继续练习的地方,比如函数与文件那部分和自己设计函数时会觉得没有头绪。