006从零开始学Python—自定义函数

01两种自定义函数及语法


虽然Python的标准库中自带了很多“方法”或函数,并且第三方模块也提供了更多的现成"方法"与函数,但有时还是不能满足需求,这时就需要自定义函数了。另外,为了避免重复编写代码并使代码简洁易读,可以将常用的代码块封装为函数,在需要时调用函数即可。


Python中两种自定义函数:

  • lambda 关键字定义的匿名函数

  • def 关键字构造有名称的自定义函数


1.lambda定义匿名函数

用lambda 关键字定义“一气呵成”的匿名函数,所有代码只能在一行内完成,语法如下:

lambda parameters:function_expression

注如上语法中:

  • lambda 为匿名函数的关键起始词;

  • parameters 是函数可能涉及的形参,如有多个参数,需要用英文状态逗号隔开;

  • function expression 为具体的函数体。

举例:

 
   
# 统计列表中每个元素的频次	
list6 = ['A','A','B','A','A','B','C','B','C','B','B','D','C']	
	
# 构建空字典,用于频次统计数据的存储	
dict3 = {}	
# 循环计算	
for i in set(list6):	
    dict3[i] = list6.count(i)	
print(dict3)	
	
# 取出字典中的键值对	
key_value = list(dict3.items())	
print(key_value)	
	
# 列表排序	
key_value.sort()	
print(key_value)	
	
# 按频次高低排序	
key_value.sort(key = lambda x : x[1], reverse=True)	
print(key_value)	
out:	
{'C': 3, 'A': 4, 'B': 5, 'D': 1}	
[('C', 3), ('A', 4), ('B', 5), ('D', 1)]	
[('A', 4), ('B', 5), ('C', 3), ('D', 1)]	
[('B', 5), ('A', 4), ('C', 3), ('D', 1)]

本案例的目的是统计列表中的元素频次,并根据频次从高到低排序。

  • 首先在统计元素频次时使用了for 循环,其中set函数是构造集合对象,可以实现列表元素的去重;

  • 然后直接对存储键值对的列表直接排序,发现默认是按照字母排序,见第三行输出,并不是以实际的频次排序;

  • 最后过构建匿名函数,对列表元素(每一个键值对元组)的第上个元素降序排序,进而实现输出结果中的最后一行效果。


2.def自定义函数

虽然匿名函数应用灵活用途很多,但最大特点也是短板,即无法通过lambda函数构造一个多行而复杂的函数。为了弥补其缺陷,Python 提供了另一个关键字def构造复杂自定义函数,语法如下:

def function_name(parameters):

function_expresslon

return(result)

注如上语法中:

  • def是define 单词的缩写,表示自定义;

  • function_name 为自定义的函数名称;

  • parameters为自定义函数的形参,需要放在圆括号内;

  • 第一行的结束必须要加上英文状态的冒号,(这是很多初学者容易忽略的细节)

  • function_expression 是具体的函数体(注意,第二行开始需要缩进),根据需求,可以简单可复杂;

  • return用于返回函数的计算结果,如果有多个值需要返回,可以全部写在return 的括号内,并以逗号隔开。

自定义函数举例:猜数字游戏

 
   
# 猜数字	
def game(min,max):	
    import random	
    number = random.randint(min,max)  # 随机生成一个需要猜的数字	
    while True:	
        guess = float(input('请在%d到%d之间猜一个数字: ' %(min, max)))	
	
        if guess < number:	
            min = guess	
            print('不好意思,你猜的的数偏小了!请在%d到%d之间猜一个数!' %(min,max))	
        elif guess > number:	
            max = guess	
            print('不好意思,你猜的的数偏大了!请在%d到%d之间猜一个数!' %(min,max))	
        else:	
            print('恭喜你猜对了!')	
            print('游戏结束!')	
            break	
	
# 调用函数	
game(10,20)	
out:	
请在10到20之间猜一个数字: 20	
不好意思,你猜的的数偏大了!请在10到20之间猜一个数!	
请在10到20之间猜一个数字: 13	
不好意思,你猜的的数偏小了!请在13到20之间猜一个数!	
请在13到20之间猜一个数字: 15	
不好意思,你猜的的数偏小了!请在15到20之间猜一个数!	
请在15到20之间猜一个数字: 18	
不好意思,你猜的的数偏大了!请在15到18之间猜一个数!	
请在15到18之间猜一个数字: 16	
恭喜你猜对了!	
游戏结束!

详情请参照《Python简明教程》


02自定义函数的四种参数


1.必选参数

在调用一个自定义函数时必须给函数中的必选参数赋值,否则程序将会报错,并提醒用户"缺少一些必选的位置参数"。

举例:以上面的猜数字函数为例,如果不给该函数的max 参数传递一个值,结果就是这样的:

 
   
TypeError	
Traceback(most recent call last)	
 in ()	
---->1 game(min=10)	
TypeError:game()missing 1 required positional argument:'max'

注:如上返回“类型错误”提示,查看最后一行反馈结论为“game函数缺少一个必要的位置参数 max”,表明 game 函数需要给 max 参数传值。


2.默认参数

默认参数是指在构造自定义函数的时候就已经给某些参数赋予了各自的初值,当调用函数时,这样的参数可以不用传值。

例如计算1到n的p次方和:

 
   
# 计算1到n的平方和	
def square_sum(n, p = 2):	
    result = sum([i ** p for i in range(1,n+1)])	
    return(n,p,result)	
	
print('1到%d的%d次方和为%d!' %square_sum(200))	
print('1到%d的%d次方和为%d!' %square_sum(200,3))	
out:	
1到200的2次方和为2686700!	
1到200的3次方和为404010000!

注:

  • 如上构造的自定义函数中,n为必选参数,p为默认参数.根据结果显示,在第一次调用面时,并没有绐p参数传递任何值,函数正常运行,而且默认计算平方和;

  • 在第二次调用函数叶p传递丁新值3,此时p参数由原来的2换成了3,进而可以计算立方和。


3.可变参数

上面讲解的必选参数和默认参数都是在己知这个自定义函数需要多少个形参的情况下构建的。如果不确定该给自定义函数传入多少个参数值时,该如何自定义函数呢?

例如,小明的弟弟小亮刚读一年级,老师布置了一些关于两个数的求和运算,针对这个问题我们可以构建如下的自定义函数:

斗两个数的求和

 
   
# 两个数的求和	
def add(a,b):	
    s = sum([a,b])    	
    return(a,b,s)	
	
print('%d加%d的和为%d!' %add(10,13))	
out:	
10加13的和为23!

如果只是两个数求和的问题可以很简单地利用自定义函数add 解决,但如果不是两个数之和而是三个数或四个数或五个数之和,也就是说不确定接下来会计算几个数的和,这时再使用上面add函数似乎就不合理了。好在Python 给自定义函数提供了可变参数,目的就是解决这类问题举例如下:

任意个数的数据求和:

 
   
# 任意个数的数据求和	
def adds(*args):	
    print(args)	
    s = sum(args)    	
    return(s)	
	
print('和为%d!' %adds(10,13,7,8,2))	
print('和为%d!' %adds(7,10,23,44,65,12,17))	
out:	
(10, 13, 7, 8, 2)	
和为40!	
(7, 10, 23, 44, 65, 12, 17)	
和为178!

注:

如上自定义函数中,参数args前面加了一个星号*,这样的参数就称为可变参数,可以接纳任意多个实参的,因为该类型的参数将这些输入的实参进行了捆绑,并且组装到元组中,正如输出结果中的第一行和第三行,就是自定义函数中print(args)语句的效果.


4.关键字参数

虽然一个可变参数可以接受多个实参,但是这些实参都被捆绑为元组了,而且无法将具体的实参指定给具体的形参。

关键字参数,既可以接受多个实参,又可以把多个实参指定给各自的实参名,而且这种参数会把带参数名的参数值组装到一个字典中,键就是具体的实参名,值就是传入的参数值。


例如某电商平台,在用户注册时,用户的手机号及出生日期为必填项,其他信息为选填项。对于选填项来说,电商平台并不知道用户会不会填,以及可能填多少个信息,而且这些信息都是有对应含义的。为了搜集信息,可以创建一个含关键字参数的自定义函数:

 
   
# 关键字参数	
def info_collection(tel, birthday, **kwargs):	
    user_info = {}   # 构造空字典,用于存储用户信息	
    user_info['tel'] = tel	
    user_info['birthday'] = birthday	
    user_info.update(kwargs)	
    # 用户信息返回	
    return(user_info)	
	
# 调用函数    	
info_collection(13612345678,'1990-01-01',nickname='月亮',	
gender = '女',edu = '硕士',income = 15000,add = '上海市浦东新区',	
interest = ['游泳','唱歌','看电影'])	
out:	
{'tel': 13612345678,	
 'birthday': '1990-01-01',	
 'nickname': '月亮',	
 'gender': '女',	
 'edu': '硕士',	
 'income': 15000,	
 'add': '上海市浦东新区',	
 'interest': ['游泳', '唱歌', '看电影']}

注:

  • 如上结果所示,在自定义函数info_collection中,tel 和 birthday 都是必选参数,kwargs为关键字参数;

  • 当调用函数时,tel和birthday 两个参数必须要传入对应的值,而其他的参数都是用户任意填写的,并且关键字参数会把这些任意填写的信息组装为字典,如输出中的第一行信息;

  • 为了把必选参数的值和关键字参数的值都汇总起来,在自定义函数时初设了空字典 user_info,并通过字典元素增加的方法完成用户信息的搜集,如输出的第二个结果。


整体感受:自定义函数是一种非常灵活有用的技能,并且可以简化代码,提高可读性。写到这里,顺便分享下如何在VBA以及SQL Server数据库中自定义函数,供大家对照学习。


VBA中定义提取中文自定义函数:

 
   
Function 提取中文(rng As String, i As Integer)	
  Dim regx As New RegExp	
  With regx	
   .Global = True	
   If i = 1 Then	
    .Pattern = "\D"	
   ElseIf i = 2 Then	
    .Pattern = "\w"	
   End If	
   提取中文 = .Replace(rng, "")	
  End With	
End Function


SQL Server中定义提取中文自定义函数:

数据库下---->可编程性---->函数---->标量值函数

 
   
CREATE FUNCTION dbo.Clear_English(@S VARCHAR(100)) 	
RETURNS VARCHAR(100) 	
AS 	
BEGIN 	
WHILE PATINDEX('%[^a-zA-Z0-9]%',@S) > 0 	
BEGIN 	
set @s=stuff(@s,patindex('%[^a-zA-Z0-9]%',@s),1,'') 	
END 	
RETURN @S 	
END 	
GO 


读书笔记内容来源:《从零开始学Python数据分析与挖掘》

你可能感兴趣的:(006从零开始学Python—自定义函数)