函数 - 定义 调用 返回值 参数

引入

如果在你的程序中有一段代码需要频繁使用,怎么办?最简单粗暴的办法就是,在程序中重复的编写这段代码。

如果这段代码的某些功能需要更改,怎么办?最简单粗暴的办法就是,找到所有用到这段代码的地方逐一进行修改。

您觉得上述的解决办法如何?--- 您要是敢这么写,分分钟被开除~

解决代码重复

上述解决问题的方式最大的问题就是代码重复,用到一次就重复一次,无疑在现实生活中也可以找到例子,比如每次用Python写程序的时候都重复装一遍解释器和pycharm吗?显然不是,只安装一次,写代码的时候直接拿来用就OK了。这里的解释器或者pycharm就是上述例子中被频繁使用的代码,可以事先准备好,用的时候直接拿来用。

在程序中具备某种功能的工具指的就是一个函数,事先准备好就是函数的定义,使用就是函数的调用。

函数定义

函数的使用必须遵循先定义再使用的原则。

函数的定义相当于把一段代码保存,然后将这段代码的内存地址赋值给函数名,函数名就是对这段代码的引用,函数的定义和变量的定义是类似的。没有定义函数直接使用就相当于在使用一个不存在的变量。

定义函数基本语法如下:

def 函数名(参数1, 参数2....):
    '''
    函数描述
    '''
    函数体代码
    return 值

'''
def - 定义函数的关键字
函数名 - 指向函数体代码内存地址,对函数体代码进行引用,函数名应该见名知意
括号 - 括号内定义参数,参数可有可无
冒号 - 括号后要加冒号,下一行缩进后书写函数体代码
函数描述 - 描述函数的具体功能,不是必要的,但是建议加上
函数体 - 实现功能的具体代码
return 值 - 函数的返回值,非必要
'''

函数的定义有三种方式,如果把函数比喻为一个工厂,函数的参数就是送进工厂的原材料,但是有些工厂是不需要外部提供原材料。

第一种:无参函数

def func():
    print('我不需要外界为我提供参数')

第二种:有参函数

def func(a, b):
    print('需要外界传参给我')
    print(a, b)

第三种,空函数

# 函数体代码为pass为空函数,可以用来在构思项目的时候用空函数代替,当代码构思完成可以将pass替换掉
def func():
    pass

函数调用与返回值

函数的使用分为定义和调用阶段,在定义函数时只检测python语法,不执行函数体代码,函数名加括号就是调用函数,只有调用函数才会执行函数体代码。

# 定义函数阶段
def func():
    print('func')
    func1()

def func1():
    print('func1')
    
# 调用函数阶段
func()

# 执行结果
func
func1

在定义函数阶段,没有语法错误,在调用阶段,两个函数的代码都在内存中,所以也没有任何错误。

如果想要获取函数体代码的执行结果,就需要用到return关键字。

return是一个函数结束的标志,一个函数中可以包含多个return,但是只要执行到其中某一个return函数就结束了,并且会把return后的值作为本次调用的结果返回。

return返回值有三种情况:

第一种,返回None

# 省略return
def func():
    print('没有return')
res = func()  # 使用变量接收函数执行后的返回值
print(res)  # None

# return后不跟返回值
def foo():
    print('return后不跟返回值')
    return
res = foo()
pritn(res)  # None

# return返回None
def func():
    return None

第二种,返回一个值,可以是任意数据类型的值

def func():
    return [1, 2]

第三种,返回多个值,用逗号分隔开,会被return返回成元组

def func():
    return 1, 2  # 相当于return (1, 2)

函数的调用也可以分为三种不同的形式。

第一种,函数名加括号直接调用

def func():
    print('func')
func()

第二种,表达式形式

def add(a, b):
   return a+b
res = add(1, 2)  # 函数返回值赋值给变量
res1 = 10 * add(1, 2)  # 对函数返回值进行计算等其他操作

第三种,函数返回值作为参数

def add(a, b):
    return a+b

res = add(1, add(2, 3))  # 将函数返回值作为函数的参数

函数的参数

形参和实参

函数的参数分为形式参数和实际参数,简称形参和实参。

形参,在定义函数时,括号内声明的参数,本质就是一个变量名,用来接收函数外部传来的值。

实参,在调用函数时,括号内传入的值,值可以是任意类型的数据。

在调用有参函数时,实参(值)会赋值给形参(变量名)。

def add(a, b):  # a b是形参,相当于变量名
    print(a + b)

add(1, 2)  # 1 ,2是实参,相当于变量值,分别赋值给a b

形参和实参具体使用

位置参数

指的是按照顺序定义的参数,需要从定义函数和调用函数两个角度去看。

在定义函数时,按照从左到右的顺序依次定义形参,称为位置形参,凡是按照这种形式定义的形参都必须被传值。

def func(x, y):
    print(x, y)
func()  # TypeError: func() missing 2 required positional arguments: 'a' and 'b'

在调用函数时,按照从左到右的顺序依次定义实参,称为位置实参,凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应。

def func(x, y):
    print(x, y)
func()  # TypeError: func() missing 2 required positional arguments: 'a' and 'b'

关键字参数

在调用函数时,实参可以是key=value的形式,称为关键字参数,凡是按照这种形式定义的实参,可以完全不按照从左到右的顺序定义,但仍能为指定的形参赋值。

def func(x, y):
    print(x, y)
func(y=10, x=12)  

需要注意的是,实参可以混合使用位置和关键字传参,但是必须保证关键字参数在位置参数后面,并且不能对同一个形参重复赋值。

def func(x, y):
    print(x, y)
func(10, y=10)  # 正确
func(x=10, 20)  # 错误
func(10, 20, y=30)  # 错误,对y重复赋值了

默认参数

默认参数,指的是在定义函数的时候就已经为形参赋值。默认参数必须在位置参数之后。

当函数有多个形参时,可以将值改变较少的参数定义成默认参数,默认参数可以在调用时修改值。

def func(x, y=1):
    print(x, y)
func(1)  # 正确
func(1, 2)  # 正确

可变长度参数以及*/**的使用

在定义函数时如果还不确定需要多少个参数,就可以使用可变长度参数占位。

参数的长度可变就是指在调用函数的时候,实参的个数可以不固定,由于实参的格式有关键字实参和位置实参,因此形参提供了两种可变长度参数---可变长度位置参数,可变长度关键字参数。

在定义函数时,如果在最后一个形参名前加*,在调用函数时,多出来的位置实参,都会被*接收,以元组的形式赋值给*后的形参,约定俗成,接收多余位置参数的形参名为args。

def func(x, y, z=1, *args):
    print(x, y, z)
    print(args)
func(1, 2, 3, 4, 5, 6)  # 实参1,2,3按照位置为形参x y z赋值,多余的被*接收作为元组赋值给args

在调用上述func函数的时候,事先有一个可迭代对象(字符串、列表、字典、元组),可以通过*将这些对象中的每个元素作为实参传递给args.

def func(x, y, z=1, *args):
    print(x, y, z)
    print(args)
func(1, 2, 3, *'abc')
# * 的作用相当于for循环,将可迭代对象中的每个元组取出作为实参,如果没有*的话,'abc'就是一个普通的位置参数

如果在定义函数时,在最后一个形参名前加**,在调用函数时,多出来的关键字参数都会被**接收,以字典的形式赋值给**后面的参数,约定俗成,接收多余关键字参数的形参名是kwargs。

def foo(x, y, z, **kwargs):
    print(x, y, z)
    print(kwargs)
foo(1, 2, 3, a=1, b=2)  # 实参1,2,3按照位置为形参x y z赋值,多余的关键字实参被**接收作为字典赋值给kwargs

在调用上述foo函数时,可以将字典作为参数,通过**将字典中的每个键值对作为关键字参数传递给函数

foo(**{'x': 1, 'y':2, 'z':3, 'a': 4})
# 这种传值方式相当于foo(x=1, y=2, z=3, a=4),如果不是用**,字典就是一个普通的位置形参

各种参数结合使用

以上所有的参数都可以组合使用,但是在定义函数时,参数的顺序必须是:位置参数、默认参数、args、kwargs。

可变长度位置参数(*args)和可变长度关键字参数(**kwargs)通常组合使用,表示该函数可以接受任何形式、任意长度的参数。

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

推荐阅读更多精彩内容