函数


函数

函数是程序中可复用的代码块。你可以给这段代码块起名字,也就是函数名。然后在程序中的任意地方去调用它。我们已经使用过内置的一些函数,比如range(), len()
函数也许是成功软件里最重要的一个组成部分,下面我们将会详述函数的各个部分。
函数使用关键字def来定义,紧跟着关键字的是函数名,后面的一对小括号里有保存传入参数的变量,在这一行的最后有个冒号,表示下面的语句块属于该函数。下面是一个简单的例子:
例子(保存至function1.py):

def say_hello():
    #属于函数的语句块
    print('你好,中国!')

say_hello()#调用函数
say_hello()#调用函数

输出:

$ python function1.py
你好,中国!
你好,中国!

它是怎么运作的呢?

我们定义了一个函数say_hello(),然后调用了两次。该函数没有传入参数,因此括号里没有变量。参数是函数的输入,因此我们可以传入不同的值,然后得到不同的返回值。
注意,我们调用了两次函数,也就是说,不用重复写代码了!


函数参数

函数可以接收多个参数,也就是你提供给函数的变量,函数可以使用这些变量,完成某个功能。参数和变量不同之处 - 参数直到调用函数的时候才会被赋值。
在函数定义的时候,参数用小括号括住,参数之间用逗号分隔。当要调用该函数时,要类似的提供参数值。注意,我们这里用的专业术语-在定义函数时,括号里的叫做参数,在调用函数时,括号里的叫做参数值。
例子(保存至function_param.py):

def print_max(a, b):
    if a > b:
        print(a, '第一个数大。')
    elif a == b:
        print('两个数一样大。')
    else:
        print(b, '第二个数大。')

print_max(3, 4)
x = 6
y = 7
print_max(x, y)

输出:

$ python function_param.py
4 第二个数大。
7 第二个数大。
它是怎么运作的呢?

我们定义了一个叫做print_max的函数,该函数有两个参数ab。我们用if语句去找到两个数中较大的一个数,然后把它打印出来。
第一次调用print_max,我们直接把数值当作参数值;第二次调用print_max,我们把变量当作参数值,print_max(x, y)把x的值赋给a,把y的值赋给b。两种情况下,print_max函数有着相同的运作方式。


局部变量

你在函数里定义的变量,与函数外的同名变量没有任何关系;也就是说,对于函数,变量名是局部的。这种情况叫做变量的作用域。变量在哪里代码块里定义的,它的作用域就在哪个代码块里, 变量作用域从定义的地方开始,直到代码块的结束位置。
例子(保存至function_local.py):

x = 50

def func(x):
    print('x 的值:', x)
    x = 2
    print('变成局部变量x的值:', x)

func(x)
print('外部x的值:', x)

输出:

$ python function_local.py
x 的值: 50
变成局部变量x的值: 2
外部x的值: 50

它是怎么运作的呢?

第一次打印的x值,在函数体的第一行,它用主代码块传进的参数值。
接下来我们把2赋值给x,x的名字只在该函数的内部生效。所以当我们在函数里改变了x的值,并不会对主代码块的x造成影响(名空间)。


全局变量

如果你想定义一个全局变量,你仅需要告知Python,这个变量名不是局部的,是全局的,就可以了。我们将使用全局变量声明。在函数里给函数外部的变量赋值,一定要使用全局变量声明。
你可以在函数里使用函数外的变量。然而这不是一个好的代码习惯,应该避免这样做,它会让你的代码不清晰,难以阅读,因为读者不知道变量定义在何处。全局变量的声明就适用在这种情况。
例子(保存至function_global.py):

x = 50

def func():
    global x
    
    print('x的值是:', x)
    x = 2
    print('变成了全局变量x:', x)

func()
print('外部x的值是:', x)

输出:

$ python function_global.py
x的值是: 50
变成了全局变量x: 2
外部x的值是: 2
它是怎么运作的呢?

全局变量声明,声明x是一个全局变量,因此外部的x可以在函数里被赋值,当然外部的x值也相应的发生了改变。
在一个全局变量声明中,你可以指定多个全局变量。比如,global x, y, z。


默认的参数值

一些函数,你可能想让一些参数是可选的,也就是说在调用的时候对这些参数可以传入参数值也可以不传入参数值,当不传入参数值的时候,函数使用该参数的默认值。参数的默认值应该在定义函数的时候定义,也就是在参数后面添加操作符=和默认值。
注意,参数的默认值必须是一个常量,准确说,参数的默认值是不能被修改的。下面的章节会对不能被修改的值做阐述。现在,记住这点就可以了。
例子(保存至function_default.py):

def say(message, times=1):
    print(message*times)

say('你好')
say('驴子', 5)

输出:

$ python function_default.py
你好
驴子驴子驴子驴子驴子
它是怎么运作的呢?

函数say用来打印字符串指定的次数。如果没有提供打印的次数,会取默认值也就是1, 那么将会打印字符串一次。可以看到,我们在定义函数的时候指定了打印次数的默认值。
在第一次调用say时,只传入了一个字符串参数,它把字符串打印了一次;第二次调用时,传入了字符串和次数,因此它把字符串打印了5次。

注意:
只有在参数列表最后端的参数能有默认值,也就是说带有默认值的参数不能在没有默认值的参数前面,哈,有点拗口。
这是因为参数依据参数列表的位置进行赋值,比如说,def func(a, b=5)是一个有效的函数,而def func(a=5, b)是一个非法的函数。


关键字参数

有些函数可能有很多参数,并且你想通过指定名字来传入参数值,这种方式叫做关键字传参。这种情况,我们使用关键字代替位置进行传参。
这种传参方式有两个优点:

  1. 函数更容易使用:因为不需要担心忘记参数的顺序。
  2. 我们可以只传入我们想要传入的参数。
    例子(保存至function_keyword.py):
def func(a, b=5, c=6):
    print('a is %s, b is %s, c is %s' % (a, b, c))

func(3, 7)
func(3, c=25)
func(b=23, a=3)

输出:

$ python function_keyword.py
a is 3, b is 7, c is 6
a is 3, b is 5, c is 25
a is 3, b is 23, c is 6
它是怎么运作的呢?

函数func有一个不带默认值的参数,后面有两个带有默认值的参数。
第一次调用函数,func(3, 7),通过位置传参,a被赋值3, b被赋值7, c取默认值。
第二次调用函数,func(3, c=25), 通过关键字和位置传参,a被赋值3, b取默认值5, c被赋值25。
第三次调用函数,func(b=23, a=3), 通过关键字传参,a被赋值3, b被赋值23, c取默认值6。


VarArgs参数

有时,你可能想要定义一个可以接收任意多个参数的函数,也就是接收个数可变的参数。可以通过使用星号来达成。
例子(保存至function_varargs.py):

def total(a=5, \*numbers, \*\*phonebook):
    print('a', a)
    for i in numbers:
        print(i)
    for key, value in phonebook.items():
        print('关键字', key)
        print('值', value)

print(total(10, 1, 2, 3, jack=1123, john=2231, inge=1560))

输出:

a 10
1
2
3
关键字 jack
值 1123
关键字 john
值 2231
关键字 inge
值 1560
None
它是怎么运作的呢?

一个星号参数,表示所有位置参数值的集合。
双星参数与它类似,表示所有关键字参数值的集合。


return语句

return语句用来从函数返回,也就是,跳出函数,但是可以从函数返回一个值。
例子(保存至function_return.py):

def maxmum(x, y):
    if x > y:
        return x
    elif x == y:
        return '一样大'
    else:
        return y
print(maxmum(2, 3))

输出:

$ python function_return.py
3
它是怎么运作的呢?

maxmum函数返回参数中最大的数,该函数用简单的if..else语句去找最大的数,然后返回这个数。
注意,一个不带值的return语句等同于return NoneNone是Python的一个特殊类型,表示无。比如说,可以用它来表示一个变量没有值。
如果你没有给函数写return语句,那么函数结尾处会隐式包含一个return None语句。some_function()没有写return语句,当执行print(some_function())时,会打印一个None。

def some_function():
    pass

pass语句表示一个空的语句块。

小提示:
内置的max函数用来找最大数,当要找最大数时,尽量用它。


文档字符串

Python有个非常棒的特性,叫做文档字符串。文档字符串是一个重要的工具,它给程序做批注,让程序更容易理解。更棒的是,我们还可以获取到在执行状态的程序的文档字符串。
例子(保存至function_docstrings.py):

def print_max(x, y):
    '''
    打印两个数中最大的数,这两个数必须是整数。
    ''' 
    if x > y:
        print(x, '是最大数')
    else:
        print(y, '是最大数')
    
print_max(3, 5)
print(print_max.__doc__)

输出:

$ python function_docstrings.py
打印两个数中最大的数,这两个数必须是整数。
它是怎么运作的呢?

在函数体第一行的注释内容就是该函数的文档字符串。注意,模块和类也有文档字符串,在后面的内容将会学到。
文档字符串,必须是多行字符串。书写惯例:第一段简单介绍功能,第二段是详细的介绍,两段间间隔一行。
如何获取文档字符串呢?在本例中,print_max函数通过它的属性__doc__来获取文档字符串。记住,Python所有都是对象,当然包括函数。
如果你用过help(),你就会明白文档字符串的作用。help所作的就是获取函数的doc属性值,然后把它漂亮的打印出来。你可以试试它,在程序中加入代码help(print_max.__doc__)。记住,按q键退出帮助窗口。
Python自动从你的程序中收集文档字符串。因此,推荐你在写的有用函数加上文档字符串。发布的Python项目有pydoc命令,它与使用help获取文档字符串类似。


总结

我们学习了函数的很多知识。但是依旧有些内容没有覆盖到。
下一章节,我们将学习使用、创建模块。

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

推荐阅读更多精彩内容