JAYのpython学习笔记——函数

个人的python学习主要参考了梁勇老师的《python语言程序设计》,函数对应第六章内容。

引言

函数用途:定义可重用代码;组织和简化代码;

定义函数

函数由函数头和函数体构成,其中函数头包括"函数名"和"形参";

def functionName(list of parameters)
	#function body

函数特性

  1. 函数头以一个"def"关键字开始,后面紧接着"函数名"以及"形参"并以冒号结束。
    1.1 参数就像一个占位符,当调用函数的时候,将一个值传递给参数,这个值就被称为实际参数or“实参”
    1.2 参数是可选的,即函数可以不包含参数,如random.random()
  2. 函数可以有返回值也可以没有(事实上不论是否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

  1. 每次调用函数时,系统就会创建一个为函数存储它的参数和变量的激活记录,然后将其放在堆栈的内存区域中,调用栈被称为执行堆栈or运行堆栈or机器堆栈,简称堆栈。当调用函数时,调用者的激活记录保持不变,为新函数的调用创建一个新的激活记录。当函数工作结束之后,程序控制权就转交到调用者手中,同时从堆栈中删除激活记录。 ↩︎
  2. 如果在同一个模块中创建了同名的函数,那么不会出现语法错误,但是后者的优先级会更高,也即后面的函数会取代前面的函数 ↩︎