JAYのpython学习笔记——函数
个人的python学习主要参考了梁勇老师的《python语言程序设计》,函数对应第六章内容。
引言
函数用途:定义可重用代码;组织和简化代码;
定义函数
函数由函数头和函数体构成,其中函数头包括"函数名"和"形参";
def functionName(list of parameters)
#function body
函数特性
- 函数头以一个"def"关键字开始,后面紧接着"函数名"以及"形参"并以冒号结束。
1.1 参数就像一个占位符,当调用函数的时候,将一个值传递给参数,这个值就被称为实际参数or“实参”
1.2 参数是可选的,即函数可以不包含参数,如random.random() - 函数可以有返回值也可以没有(事实上不论是否return,所有python函数都将返回一个值,没有的时候,返回特殊值None,所以无返回值函数也可以叫做None函数)
2.1 有返回值的函数被称为带返回值的函数,需要一个return关键字来返回一个值,执行了return语句,意味着函数的终止
调用函数
带返回值的函数调用
large = max(3,4)
不带返回值的函数调用
print("Programming is fun!")
以下展示一个完整代码:
def max(num1,num2)
if num1 > num2:
result = num1
else:
result = num2
return result
def main():
i=5
j=2
k=max(i,j) #call the max function
print("The larger number of", i, "and", j, "is", k)
main() #call the main function
这里的main函数定义在max之后,Python中函数可在内存中被调用,所以函数可以写在脚本文件的任何位置。堆栈采用后进先出的方式存储激活记录,假设函数m1调用m2,m2调用m3,运行时系统将m1的激活记录压栈,然后将m2的压栈,最后m3,完成m3之后,m3的激活记录先被弹出。
tip:调用栈。1
位置参数和关键字参数
函数实参是作为"位置参数"和"关键字参数"被传递的
def nPrintIn(message, n):
for i in range(n)
print(message)
可以使用nPrintIn(‘A’, 3)来输出A三次,函数将A传递给message,将3传递给n,然后输出3次,但是将顺序颠倒,那么就有不同的含义了,类似这样的参数,我们就称之为位置参数。
实参必须和函数头中定义的形参在顺序、个数、类型上匹配!
使用关键字参数可以规避这样的风险,并且参数顺序可以任意。
nPrintIn(n=5, message="good")
位置参数和关键字参数可以同时出现,但是位置参数不能出现在任何关键字参数之后。
def f(p1,p2,p3):
f(30, p2=4, p3=10) # √
f(3, p2=4, 10) # ×
通过传引用来传递参数
在python中,我们需要建立一个观念,即所有数据都是对象,每一个用变量描述的对象其实都是指向对象的引用,即声明实参时,引用的值通过实参传递给形参,被称为值传递,那么当我们对声明的实参做修改时,此时的形参值是不发生改变的。
def mian():
x=1
print("Before the call, x is", x)
increment(x)
print("After the call, x is", x)
def increment(n)
n += 1
print("\tn inside the function is", n)
main()
Before the call, x is 1
n inside the function is 2
After the call, x is 1
之所以在对对象操作之后,实参的值不发生变化,因为数字和字符串都是不可变对象,当年将新数字赋值给变量时,python就会为新数字创建变量。并将新对象的引用赋值给变量。
>>> x = 4
>>> y = x
>>> id(x) #the reference of x
>>> 505408920
>>> id(y) #the reference of y is the same as the reference of x
>>> 505408920
>>> y = y + 1 #y now points to a new int object with value 5
>>> id(y)
>>> 505408936
模块化代码
在python中我们可以将函数的定义放在我们自己创建的文件中,简称模块,即以.py为后缀的文件,可以供我们反复使用。
例如我们创建一个名为GCDFunctio.py的文件
#return the gcd of two integers
def gcd(n1, n2):
gcd = 1 #initial gcd is 1
k = 2 #possible gcd
while k <= n1 and k <= n2:
if n1 % k == 0 and n2 % k == 0:
gcd = k #update gcd
k += 1
return gcd #return gcd
现在编写一个使用gcd的函数
from GCDFunction import gcd #import the gcd function
#prompt the user to enter two integers
n1 = eval(input("enter the first integer: "))
n2 = eval(input("enter the second integer: "))
print("the greatest common divisor for", n1, "and", n2, "is", gcd(n1, n2))
如果代码中只写了import GCDFunction,那么就必须以GCDFunction.gcd才能调用函数
enter the first integer: 45
enter the second integer: 75
the greatest common divisor for 45 and 75 is 15
tip:创建同名函数2
模块化的好处
1、将单独函数和主函数分开,这样程序的逻辑性和可读性会更强
2、最大公约数的功能被限制在一个函数中,缩小了调试的范围
3、其他程序可以重复利用函数gcd了
变量的作用域
定义:指该变量可以在程序中被引用的范围
局部变量:在函数内部创建的变量,作用域从创建变量的地方开始,到包含该变量的函数结束为止
全局变量:在所有函数外创建,可以被所有函数访问,允许修改全局变量不是一个好习惯,容易使程序出错
example1
globalVar = 1
def f1():
localVar = 2
print(globalVar)
print(localVar)
f1()
print(golbalVar)
print(localVar) #out of scope, so this gives an error
example2
x = 1
def f1():
x = 2
print(x)
f1()
print(x)
example3
x = eval(input("enter a number:"))
if x > 0:
y = 4
print(y) #this gives an error if y is not created
example4
sum = 0
for i in range(5)
sum += 1
print(i)
example5
x = 1
def increase():
global x
x = x + 1
print(x) #display 2
increase()
print(x) #display 2
默认参数
def printArea(width = 1, height = 2):
area = width * height
print("width:", width, "\theight:", height, "\tarea:". area)
printArea() #默认参数
printArea(4, 2.5) #位置参数
printArea(height = 5, width = 3) #关键词参数
printArea(width = 1.2)
printArea(height = 6.2)
函数可以混用默认参数和非默认参数,但是非默认参数需要定义在默认参数之前
尽管很多语言支持定义同名参数,但是python不支持,通过默认参数只能定义一次
返回多个值
python允许返回多个值
def sort(num1, num2)
if num1 < num2:
return num1, num2
else:
return num2, num1
n1, n2 = sort(3,2) #调用时,需要同时赋值
print("n1 is", n1)
print("n2 is", n2)
n1 is 2
n2 is 3
- 每次调用函数时,系统就会创建一个为函数存储它的参数和变量的激活记录,然后将其放在堆栈的内存区域中,调用栈被称为执行堆栈or运行堆栈or机器堆栈,简称堆栈。当调用函数时,调用者的激活记录保持不变,为新函数的调用创建一个新的激活记录。当函数工作结束之后,程序控制权就转交到调用者手中,同时从堆栈中删除激活记录。 ↩︎
- 如果在同一个模块中创建了同名的函数,那么不会出现语法错误,但是后者的优先级会更高,也即后面的函数会取代前面的函数 ↩︎