每日一课 | 详解抽象之函数
昨天
Python大本营每日一课
抽奖之函数
DAY06
在实际应用中,通常以函数作为一个基本的代码单元,对一组需求进行抽象,用于完成一项具体的任务。函数能提高应用的模块性和代码的重复利用率。在前面的文章中,我们已经接触到了 Python 提供的一些内建函数,比如 print()、sqrt()、append()、pop()。除了 Python 提供的内建函数,我们也可以自己创建函数,这种函数被称为用户自定义函数。
public static String getPath(String basePath, String fileName)
def getPath(basePath, fileName):
def getName():
def compare(parameter1, parameter2):
if (parameter1 > parameter2):
print(1)
elif (parameter1 == parameter2):
print(0)
else:
print(-1)
#调用函数
compare(123,456)
compare(3.14,1.5)
compare(12,12.1)
1
-1
参数传递变量与引用在 Python 中,所有类型:函数、模块、数字、字符串、列表、元组、字典等等都是对象,而变量是没有类型的,怎么理解呢?请看如下实例:
print("a=", a)
a = "ABCDE"
print("a=", a)
a = [1,2,3,4,5]
print("a=", a)
a = (1,2,3,4)
print("a=", a)
a = {'key':12,'key1':13}
print("a=", a)
执行结果:
a= 12a= ABCDEa= [1, 2, 3, 4, 5]a= (1, 2, 3, 4)a= {'key': 12, 'key1': 13}
从上面的例子可以看出,同一段代码中,同一个变量 a 先后被赋值整数、字符串、列表等多种类型,这是因为变量本身没有类型,它仅仅只是一个对象的引用(指针),它可以引用任何类型,上面例子中,变量 a 先后引用多种数据类型,本质上也仅仅是改变指向而已。
不可变类型。
上文提及,变量没有类型,仅仅作为对象的引用,我们可以在深化一下,如下例子:
a = 12a = 15
上述过程的实质就是:首先创建一个对象 12,让 a 指向它,然后再创建一个对象 15,再让 a 指向后者,而前者12就被丢弃。这个过程是通过创建新的对象来实现的,并不是直接改变 a 的值,一定要理解其中区别。
这种只能通过创建新的对象才能改变对变量的赋值的数据类型,称为不可变类型,如整数、字符串、元组都是不可变类型。再来看一个例子:
x = 10
a = 5
change(a)
print("a=",a)
执行结果:
a= 5
调用 change() 函数并没有改变变量 a 的内容,这是因为,定义了一个变量 a,a 指向数字 5,然后执行 change 函数,是复制 a 到 x,刚开始 x 也指向数字5,在函数体内执行 x=10,由于整数是不可变对象,所以将创建一个新的对象 10,并将 10 赋值给 x 变量,此时 x 指向10,而 a 本身并没有发生改变,仍然指向5。
在 Python 中,对于不可变对象,调用自身的任意方法,并不会改变对象自身的内容,这些方法会创建新的对象并返回,保证了不可变对象本身是永远不可变的。
可变类型
与不可变类型相对就是可变类型,包括列表、字典、集合、队列等。如下例子:
x.append(2012)
a = [1,2,3,4]
change(a)
print("a=",a)
执行结果:
a= [1, 2, 3, 4, 2012]
很明显,a 发生了改变,原因分析:执行 change() 方法时,x 指向列表 [1,2,3,4]
,因为列表是可变对象,执行 x.append(5) 时,并不会产生新的对象,而是直接作用在原来列表对象 [1,2,3,4]
上,进而列表对象改变为 [1,2,3,4,5]
。
函数的参数类型
Python 中,函数的参数有四种类型:必须参数、关键字参数、默认参数和不定长参数。
必须参数
函数在定义的时候,已经声明了参数的数量,我们在调用函数的时候,参数的数量必须与声明时一致,且要注意顺序。
实例1:参数数量要对应。
#声明参数为一个def update(arg): arg = arg + 1
#正确update(12)#不正确,参数缺失update()#不正确,参数多余update(1,2)
实例2:参数顺序要一致。
def printInfo(name, sex, age): print("name:",name) print("sex:",sex) print("age:",age)
#正确printInfo("Jack","female", 18)#错误,参数顺序不对应printInfo(18,"Jack","female")
关键字参数
上面已经提到,调用函数时,不仅参数数量要相等,还要顺序匹配。在 Python 中,还有一种方式可以更灵活的匹配参数:函数调用使用关键字参数来确定传入的参数值。
如下实例
def printInfo(name, sex, age): print("name:",name) print("sex:",sex) print("age:",age)
#都是正确的printInfo(name="Jack",sex="female",age=18)printInfo(sex="female",name="Jack",age=18)printInfo(sex="female",age=18,name="Jack")
默认参数
有些场景下,如果调用函数时,参数错误可能会导致不可预期的严重后果,因此,为了增强函数的适应性和容错性,可以采取一种策略:调用函数时,如果没有传递参数,则会使用默认参数。如下实例:
#声明参数为一个def printInfo(name, sex, age=0): print("name:",name) print("sex:",sex) print("age:",age)
#正确printInfo(name="Jack",sex="female")
不定长参数
有些场景下,我们希望设计一个参数数量不确定的函数,如任意个整数求和,调用形式可以是:sum(a)、sum(a,b,c)、sum(a,b,c,d)……,这时候我们需要使用一种不定长参数,一般定义形式如下:
functionbody
加了(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。如下实例:
def sum(num, *num_list):
sum = num
for element in num_list:
sum += element
print("sum=",sum)
sum(1)
sum(1,2,3,4)
执行结果:
sum= 10
Return 语句
return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的 return 语句返回 None,表示没有任何值。如果函数没有显式的使用 return 语句,Python 函数也会默认返回 None 对象。
def compare(parameter1, parameter2):
if (parameter1 > parameter2):
return 1
elif (parameter1 == parameter2):
return 0
else:
return -1
result = compare(123,456)
print("result=",result)
执行结果:
result= -1
变量作用域
在前面章节的学习中,读者应该注意到一个问题,变量的使用非常多,有些地方甚至同名,那么,它们会不会冲突呢?实例如下:
a = 123
def function():
a = 10 #这里的 a 是局部变量
print("I a=",a)
function()
print("II a=",a)
执行结果:
II a= 123
上述实例可见,同名的变量并没有发生冲突,这是因为它们的“作用域”不同,变量只在自己的作用域内有效,a=123 处属于全局变量,function() 函数内部 a=10 属于局部变量,作用域不同,因此并不会冲突。
作用域分类
按作用域不同,变量可分为四种类型:L(Local),局部作用域;E(Enclosing),闭包函数外的函数中;G(Global),全局作用域;B(Built-in),内建作用域;
使用变量时,会根据作用域进行查找,优先级顺序为:L –> E –> G –>B,即在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。关于变量作用域的更多内容可查看博文《Python 变量作用域》。