深入浅出了解python函数

为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数

一、定义函数

def 函数名():
    代码
Demo(一个打印‘hello word的使用’):

def function():
    print("hello word")

二、调用
函数名()
Demo:

 function()

注:我们python是一个非编译语言,我们在调用函数时要在函数的定义下边,否则会报错

在使用过程中调用函数名加上一个小括号就可以了,如果不加()那么是一个函数的引用,不能够成功调用

三、函数的分类
函数根据有没有参数,有没有返回值,可以相互组合,一共有4种
无参数,无返回值
此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数
无参数,有返回值
此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数
有参数,无返回值
此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数
有参数,有返回值
此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数

四、文档说明

def demo(a,b):
    "用来计算2个数的和"
    return a+b

# 可以执行
help(demo)

查看函数的相关说明,一般情况函数的文档说明包含:参数说明、函数作用、返回值三部分

五、变量
1)局部变量
局部变量,就是在函数内部定义的变量
其作用范围是这个函数内部,即只能在这个函数中使用,在函数的外部是不能使用的
因为其作用范围只是在自己的函数内部,所以不同的函数可以定义相同名字的局部变量(打个比方,把你、我是当做成函数,把局部变量理解为每个人手里的手机,你可有个iPhone8,我当然也可以有个iPhone8了, 互不相关)
局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储
当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了
比如在讲到for循环的时候

for i in range(10):
  print(i)

i 就是相当于局部变量 在其他位置不能使用只能在for循环中使用。
在函数中局部变量就是在函数中定义的变量

** 2)全局变量**
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量
打个比方:有2个兄弟 各自都有手机,各自有自己的小秘密在手机里,不让另外一方使用(可以理解为局部变量);但是家里的电话是2个兄弟都可以随便使用的(可以理解为全局变量)
全局变量可以说在函数外面定义的变量,所有函数都可以使用到

demo:

# 定义全局变量
a =100

def test1():
    print(a)# 虽然没有定义变量a但是依然可以获取其数据

def test2():
    print(a)# 虽然没有定义变量a但是依然可以获取其数据

# 调用函数
test1()
test2()

全局变量能够在所有的函数中进行访问
全局变量和局部变量名字相同
demo:

a = 100 #定义全局变量

def func():
    a = 10 # 定义局部变量,和全局变量名相同
    print(a) #函数内在输出时是局部的10,而不是100

print(a) #函数外面输出100 局部变量在函数外面无法访问

局部变量会覆盖全局变量,在局部变量所在的块或者函数内,对变量的操作不影响全局变量的值,全局变量不起作用,在局部变量所在的代码块或函数外部,全局变量才起作用。

这就是变量作用域的问题。

如果我们想在函数中修改全局变量而不是局部变量,那么我们需要使用global进行声明

a = 100 #定义全局变量

def func():
    global a # 声明使用全局变量
    a = 10
    print(a) #在输出时是局部的10

print(a) # 输出10 global 声明后将全部变量进行修改

六、参数

为了让一个函数更通用,即想让它计算哪两个数的和,就让它计算哪两个数的和,在定义函数的时候可以让函数接收数据,就解决了这个问题,这就是 函数的参数(接收到的参数就可以当做局部变量来使用,python中没有指针,参数的传递有两种方式:值传递、引用传递。一般我们用的是引用传递)

参数在这里有分为形参和实参。我们可以理解形参就是函数上面定义时接收的变量名,实参就是调用的时候传递的参数。一般我们讲到的参数就是指的形参,即函数定义时的参数。

1)形参

demo:

#定义一个函数作用是进行两个数进行相加,在这里a,b就是参数
def add2num(a,b):
    c = a +b
    pring(c)

add2num(10,20) #调用函数计算两个数的和

我们的python解析器首先去定义函数add2num,然后在进行时调用函数,调用时传递两个参数,分别给a,b

然后程序会走到c = a + b进行计算,最后打印结果。

  • 缺省参数(在形参中默认有值的参数,称之为缺省参数)
    调用函数时,缺省参数的值如果没有传入,则取默认值。

demo:
下例会打印默认的age,如果age没有被传入:

def printinfo(name, age=35):
    # 打印任何传入的字符串
    print("name: %s"% name)  
     print("age %d"% age)

# 调用printinfo函数
printinfo(name="miki")

# 在函数执行过程中 age去默认值35
printinfo(age=9,name="miki")

以上实例输出结果:
name: miki
age:35
name: miki
age:9

注意:带有默认值的参数一定要位于参数列表的最后面

  • 不定长参数(有时可能需要一个函数能处理比当初声明时更多的参数, 这些参数叫做不定长参数,声明时不会命名。)
def functionname([formal_args,] *args, **kwargs):
    """函数_文档字符串"""

    function_suite
    return[expression]

加了星号(*)的变量args会存放所有未命名的变量参数,args为元组

而加**的变量kwargs会存放命名参数,即形如key=value的参数, kwargs为字典.

def fun(a, b, *args, **kwargs):
 """可变参数演示示例"""

     print("a =%d"% a)
     print("b =%d"% b)
     print("args:")
     print(args)
     print("kwargs: ")
     forkey, valueinkwargs.items():
         print("key=%s"% value)

 fun(1,2,3,4,5, m=6, n=7, p=8)# 注意传递的参数对应

以上打印结果:
a =1
b =2
args:(3,4,5)

kwargs: 
p =8
m =6
n =7

第二次传递参数:

 c = (3,4,5)
 d = {"m":6,"n":7,"p":8}
 fun(1,2, *c, **d)# 注意元组与字典的传参方式

打印结果
a =1
b =2
args:(3,4,5)

kwargs:
 p =8
m =6
n =7

第三次调用

fun(1,2, c, d)# 注意不加星号与上面的区别

打印结果:
a =1
b =2
args:
((3,4,5), {'p':8,'m':6,'n':7})

kwargs:
注:如果很多个值都是不定长参数,那么这种情况下,可以将缺省参数放到 args的后面, 但如果有kwargs的话,kwargs必须是最后的*

2)实参

实参就是函数在调用时小括号里面写入的参数,实参可以传递一个值,也可以是一个引用。在后面的学习里形参还可以传递一个对象,或者是一个函数。因为他们都是一个引用,可以当做一个参数来传递。

注意在使用中传递的参数实参数据类型要和接收方形参的数据类型一致。

七、返回值

所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果

想要在函数中把结果返回给调用者,需要在函数中使用return

如下示例:

def add2num(a, b):
    c = a+b
    return c

在返回后的数据一般情况我的会使用或者保存的这个值,那么我们可以用一个变量名去接收

#调用函数,顺便保存函数的返回值

result = add2num(100,98)

print(result)

1)返回多个值

有的函数返回的结果不仅仅只有一个,那么我们应该怎么做呢?

defdivid(a, b):
    shang = a//b
     yushu = a%b
    return shang, yushu#默认是元组

result = divid(5,2)
print(result)# 输出(2, 1)

# 返回的值是一个元组,我们可以进行拆包

a,b =  divid(5,2)
print(a) #打印结果为2
print(b) #打印结果为1

注:返回的数值一定要一一对应才可以正常拆包

return后面可以是元组,列表、字典等,只要是能够存储多个数据的类型,就可以一次性返回多个数据

def function():
    # return [1, 2, 3]
    # return (1, 2, 3)
    return{"num1":1,"num2":2,"num3":3}

2)多个return

def create_nums():

    print("---1---")

    return1# 函数中下面的代码不会被执行,因为return除了能够将数据返回之外,还有一个隐藏的功能:结束函数

    print("---2---")

    return2

    print("---3---")

一个函数中可以有多个return语句,但是只要有一个return语句被执行到,那么这个函数就会结束了,因此后面的return没有什么用处。

def create_nums(num):
    print("---1---")
    if num ==100: 
         print("---2---")
        return num+1# 函数中下面的代码不会被执行,因为return除了能够将数据返回之外,还有一个隐藏的功能:结束函数
    else: 
         print("---3---")
        return num+2

 result1 = create_nums(100) 
 print(result1)# 打印101
result2 = create_nums(200)
 print(result2)# 打印202

八、匿名函数

用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。

lambda函数的语法只包含一个语句,如下:

lambda[arg1 [,arg2,.....argn]]:expression

如下实例:

sum =lambda arg1, arg2: arg1 + arg2
#调用sum函数
print("Value of total : ", sum(10,20))
print("Value of total : ", sum(20,20))

以上实例输出结果:

Value of total :30
Value of total :40

Lambda函数能接收任何数量的参数但只能返回一个表达式的值

匿名函数不能直接调用print,因为lambda需要一个表达式

lambda函数一般情况下会当做一个参数来传递,比如做字典的排序。或者放到高级函数中使用,后面会有讲到。

九、函数的嵌套调用

在一个函数中嵌套调用另外一个函数,就是函数的嵌套调用。

deftestB():

    print('---- testB start----') 

     print('这里是testB函数执行的代码...(省略)...') 

     print('---- testB end----')

deftestA():

    print('---- testA start----') 

     testB() 

     print('---- testA end----') 

testA()

运行结果:

---- testA start----
---- testB start----
这里是testB函数执行的代码...(省略)...
---- testB end----
---- testA end----

image

十、递归

如果一个函数在内部不调用其它的函数,而是自己本身的话,这个函数就是递归函数。

举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n

def func(num):
    if num > 1:
        reault = num * **func(num-1)**
    else:
        reault = 1
    return reault
func(5)
image

十一、闭包
闭包也具有提高代码可复用性的作用。后边讲到的装饰器就是用到闭包的原理

定义一个函数

def test(number):
# 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
    def test_in(number_in):
        print("in test_in 函数, number_in is %d"% number_in)
        return number+number_in #number_in其实是一个函数的引用,是把函数的引用当做参数来传递
    # 其实这里返回的就是闭包的结果
    return test_in  #返回一定是内部函数的引用,不能带有小括号
# 给test函数赋值,这个20就是给参数
ret = test(20)        # 在这里执行的是test函数,然后将test_in函数的引用返回,重新赋值给ret
# 注意这里的100其实给参数
print(ret(100))   #在这里使用的ret(100)  相当于test_in(100)  也就相当于 test(20)(100) 最终返回的是 20+100

#注 意这里的200其实给参数

print(ret(200))   #在这里使用的ret(100)  相当于test_in(200)  也就相当于 test(20)(200) 最终返回的是 20+200

由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

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

推荐阅读更多精彩内容