python--------函数【定义、调用、传递参数、递归函数】

@[toc]

1.什么是函数

  • 函数(function)由若干条语句组成,用于实现特定的功能
  • 函数的本质就是对功能的封装
  • 一旦定义了函数,就可以在程序中需要实现该功能的位置调用函数
  • 函数名不能重复(没有重载)

2.定义和调用函数

  • 使用def关键字来创建python自定义函数
  • 可以直接使用函数名来调用函数

语法结构:

def 函数名 (参数列表)
    函数体
    return 数据
  • 参数列表可以为空,也可以包含多个参数
  • return 可写可不写,不写默认返回None

<1> 定义一个空函数

def test():
    pass

<2> 无参函数

def test():
    print('in test')
test()

运行结果

in test

==尽管定义了函数,只要不调用函数,那这个函数是不会执行的==

def hh():
    print('hello')
 #没有调用这个函数,该函数不执行

<3> 有参函数 (参数---argument/arg)

def test1(arg):
    print('in test')
test1(1)

def test2(arg):
    print('in test',arg)
    #参数类型没有要求,可以是任意类型
test2(1)
test2('hello')
test2([100,200])

def test3(arg,arg1,arg2):
    print('in test',arg,arg1,arg2)
    # 1-->arg  python-->arg1  [1,2]-->arg2
test3(1,'python',[1,2])

运行结果

in test
in test 1
in test hello
in test [100, 200]
in test 1 python [1, 2]
  • 参数类型没有要求,可以是任意类型
  • 参数的个数没有要求

3. 返回值

def test(arg,arg1,arg2):
    print('in test',arg,arg1,arg2)
    return 1  #返回1
ret=test(1,2,3)   #调用test(1,2,3)函数,然后把返回值给ret变量
print(ret)

运行结果

in test 1 2 3
1

==可以返回任何类型==

def test1(arg,arg1,arg2):
    print('in test1',arg,arg1,arg2)
    return [4,5]
ret=test1(1,2,3)
print(ret)

def test2(arg,arg1,arg2):
    print('in test2',arg,arg1,arg2)
    return [arg,arg1,arg2]
ret=test2(1,2,3)
print(ret)

运行结果

in test1 1 2 3
[4, 5]
in test2 1 2 3
[1, 2, 3]

==如果没有return那么就返回None return|return None |不写==

def test3(arg,arg1,arg2):
    print('in test3',arg,arg1,arg2)
ret=test3(1,2,3)
print(ret)


def test4(arg,arg1,arg2):
    print('in test4',arg,arg1,arg2)
    return
ret=test4(1,2,3)
print(ret)

def test5(arg,arg1,arg2):
    print('in test5',arg,arg1,arg2)
    return None
ret=test5(1,2,3)
print(ret)

运行结果

in test3 1 2 3
None
in test4 1 2 3
None
in test5 1 2 3
None

<font color=Blue size=5> 练习题:</font>

#我们系统函数test6 如果都是整数 那么返回数组[1,2,3]
#如果参数全是字符串 就返回 arg arg1 arg2 'welcome to python'

def test6(arg,arg1,arg2):
    #判断参数的类型
    #isinstance 是系统的 用来判断参数是否是你想要的那个类型
    if isinstance(arg,int) and isinstance(arg1,int) and isinstance(arg2,int):
        return [arg,arg1,arg2]
    if isinstance(arg,str) and isinstance(arg1,str) and isinstance(arg2,str):
        return arg+' '+arg1+' '+arg2
    #如果参数并不都是整数或者并不都是字符串,那就返回'Error'
    return 'Error'
c=test6(1,2,3)
print(c)
c=test6('welcome','to','python')
print(c)
c=test6(1,2,'python')
print(c)

运行结果

[1, 2, 3]
welcome to python
Error

4.形参和实参

形参:

  • 形参变量只有在被调用时才分配内存单元,在调用结束时,即可释放预分配的内存单元
  • 形参只在函数内部有效
  • 函数调用结束返回主调用函数后则不能再使用该形参变量

实参:

  • 实参可以是常量、变量、表达式、函数等
  • 无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传递给形参
  • 应预先用赋值,输入等办法是参数获得确定值
def calc(x,y): #x,y是形参
    res=x**y
    return res
c=calc(2,3)   #2,3是实参
#有人想这个不就是 x=2,y=3的赋值操作,那就可以直接输出x,y
#但是不要忘了形参只有在被调用时才分配内存单元
#print(x)   错误
#print(y)   错误
print(c)

运行结果

8

5.函数参数

def test7(name,age,score):
    print(name,age,score)

<1>普通参数

test7('yang',18,80)

运行结果

yang 18 80

==普通参数的参数顺序不能改变==

tset7(18,'yang',80)  是错的

<2> 关键字参数

==顺序可以随便设置==

test7(name='yang',age=18,score=80)
test7(age=18,score=80,name='yang')

运行结果

yang 18 80
yang 18 80

<3> 普通参数和关键字参数混合使用

  • 注意python要求 普通参数和关键字参数如果混合使用那么你必须==先传普通参数,然后再传关键字参数==
test7('yang',18,score=80)
test7('yang',age=18,score=80)
test7(name='yang',age=18,score=80)
#test7('yang',age=18,80)   错误
#test7('yang',70,age=18)    错误  70传给age而后面的参数又给age赋值了一个数,那就没有参数传给score了

运行结果

yang 18 80
yang 18 80
yang 18 80

<4>默认参数

def test8(name,age,score=60):
    print(name,age,score)
#因为已经有一个参数有了默认值,所以我们传入两个参数就可以
test8('yang',18)
#当然也可以传三个参数,但是已经默认的那个参数如果也要传的话,它会自动变为传入的数值
test8('yang',18,70)

运行结果

yang 18 60
yang 18 70

==默认参数后面不能有普通参数==

def test9(name,age=18,score=80):
    print(name,age,score)
test9('yang')
# def test9(name,age=18,score):    错误

运行结果

yang 18 80

<5> 可变长参数

(1) *args

  • *args表示一个可变元组
  • args就是一个元组 元组就是只读的数组/列表
  • 参数名就是args
  • *表示 args里面的参数可变
def test10(*args):
    print(args)
test10(1,2,3)   #可以随便添加参数

运行结果

(1, 2, 3)
def test11(*args):
    print(args,type(args)) #只输出args的值和类型
    value=0
    for i in args: #因为args是一个元组,所以需要遍历才能获取每个元素
        value+=i
    return value
c=test11(1,2,3,4)
print(c)
c=test11()   #没有给args传值
print(c)

运行结果

(1, 2, 3, 4) <class 'tuple'>
10
() <class 'tuple'>
0

这个可变参数 前面两个参数v1,v2是默认参数,后面的参数是可变的

def test12(v1,v2,*args):
    print(args,type(args))  #只输出args的值和类型
    value=0
    for i in args:
        value+=i
    return value
c=test12(1,2)    #v1=1,v2=2,没有给args传值
print(c)

运行结果

() <class 'tuple'>
0
def test13(v1,v2,*args):
    print(args,type(args))   #只输出args的值和类型
    value=0
    for i in args:
        value+=i
    return value
c=test13(1,2,3)    #v1=1,v2=2,args=3
print(c)

运行结果

(3,) <class 'tuple'>
3
def test14(v1,v2,*args):
    print(args,type(args))   #输出args和args的类型
    value=(v1+v2)    #value不像前两个赋值为0,现在的value已经把v1,v2提前加起来了
    for i in args:
        value+=i
    return value
c=test14(1,2,3)    #v1=1,v2=2,args=3
print(c)

运行结果

(3,) <class 'tuple'>
6

可变参数传数组/列表
*list1就是args

def test14(v1,v2,*args):
    print(args,type(args))   #输出args和args的类型
    value=(v1+v2)    #value不像前两个赋值为0,现在的value已经把v1,v2提前加起来了
    for i in args:
        value+=i
    return value
list1=[1,2,3,4]
c=test14(1,2,1,100,*list1)   #v1=1 v2=2 1,100,*list1就是args
#上面的相当于拆成 c=test14(1,2,1,100,1,2,3,4)
print(c)
(1, 100, 1, 2, 3, 4) <class 'tuple'>
114

(2) **kwargs

  • 可变参数处理关键字参数
  • kwargs表示 关键字可变参数
  • *表示普通可变参数(positional 位置参数)
  • ** 表示关键字可变参数
  • kwargs是一个字典
def test15(**kwargs):
    print(kwargs,type(kwargs))
    value=0
    for key in kwargs:
        v=kwargs[key]  #获取字典里的值
        if isinstance(v,int) or isinstance(v,float): #如果v是整数或者是浮点数那就执行下面的加法运算
            value+=v
    return value
test15(name='yang')
c=test15(name=10,b=1,c=2,d=3,e=4,f=100.56)
print(c)

运行结果

{'name': 'yang'} <class 'dict'>
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56} <class 'dict'>
120.56

==可变参数支持位置参数/普通参数和关键字参数==

def test16(*args,**kwargs):
    print(args)
    print(kwargs)
    value=0
    return  value
c=test16(1,2,3,name=10,b=1,c=2,d=3,e=4,f=100.56)
print(c)

运行结果

(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
0
def test17(*args,**kwargs):
    print(args)
    print(kwargs)
    value=0
    #先处理位置参数/普通参数
    for i in args:    #遍历元组
        value+=i
    for i in kwargs:   #遍历字典
        v=kwargs[i]
        value+=v
    return  value
c=test17(1,2,3,name=10,b=1,c=2,d=3,e=4,f=100.56)  #若有字符串的参数还需要判断并不参与加法运算
print(c)

运行结果

(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
126.56

参数解开

dict2={'name':10,'b':1,'c':2,'d':3,'e':4,'f':100.56}
tuple2=(1,2,3)
# *tuple2 表示把(1,2,3)---->1,2,3
# **dict2 表示把{'name':10,'b':1,'c':2,'d':3,'e':4,'f':100.56}--->name=10,b=1,c=2,d=3,e=4,f=100.56
#  **的作用就是把dict2从字典转换成关键字参数
c=test17(*tuple2,**dict2)
print(c)

运行结果

(1, 2, 3)
{'name': 10, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 100.56}
126.56

6.递归函数

递归特性

  • 必须有一个明确的结束条件
  • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  • 递归效率不高,递归层次过多会导致栈溢出
  • 在计算机中,函数调用时通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的。所以,递归调用的次数过多,会导致栈溢出
def calc(n):
    print(n)
    if int(n/2)==0:
        return n
    res=calc(int(n/2))
    return res
calc(10)

运行结果

10
5
2
1
def calc1(n):
    print(n)
    if int(n/2)==0:
        return n
    res=calc1(int(n/2))
    return res
res=calc1(10)
print(res)

运行结果

10
5
2
1
1
在这里插入图片描述

res的值就是最后得到的1

递归函数相当于问路,我问1号朋友怎么去目的地,1号不知道他去2号,2号不知道他去问3号,3号说我知道怎么走,这时,我们还要返回正确路线给问路人我,3号告诉2号,2号告诉1号,1号再传达给我

person_list=['小明','小李','小红','小蓝']
def ask_way(person_list):
    print('-'*60)    #打印一条分界线
    if len(person_list)==0:   #到最后一个人还不知道怎么走
        return '没人知道'
    person=person_list.pop(0)  #每次都把列表里的第0个元素删除并赋值给person
    if person=='小红':     #小红知道正确的路线
        return '%s说:我知道路,左走一百米就到了'%person
    print('hi 美女[%s],请问你知道华林在哪吗?'%person) #每当问到一个人就输出这句话
    print('%s回答道:不好意思,我不是很清楚,我帮你问问%s...'%(person,person_list))
    res=ask_way(person_list)   #把继续问的人的结果赋值给res,当结果问到时就一层一层的返回给问路的人,并输出下面的话
    print('%s问的结果是:%res'%(person,res))
    return res
res=ask_way(person_list)
print(res)

运行结果

------------------------------------------------------------
hi 美女[小明],请问你知道华林在哪吗?
小明回答道:不好意思,我不是很清楚,我帮你问问['小李', '小红', '小蓝']...
------------------------------------------------------------
hi 美女[小李],请问你知道华林在哪吗?
小李回答道:不好意思,我不是很清楚,我帮你问问['小红', '小蓝']...
------------------------------------------------------------
小李问的结果是:'小红说:我知道路,左走一百米就到了'es
小明问的结果是:'小红说:我知道路,左走一百米就到了'es
小红说:我知道路,左走一百米就到了
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容

  • 原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...
    小猪啊呜阅读 4,599评论 1 19
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,776评论 0 38
  • 第5章 函数和函数式编程 5.1 引言函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数...
    VIVAFT阅读 950评论 0 5
  • 函数只定义一次,但可能被执行或调用任意次。JS函数是参数化的,函数的定义会包括一个称为形参的标识符列表,这些参数在...
    PySong阅读 847评论 0 0
  • 朋友,你在想什么? 很多人都在想,我腿上毛发那么茂盛,还不好看,头上头发少也不好看,为什么不能废物利用,将腿毛种到...
    美发设计馨馨阅读 227评论 2 0