带你学python基础:函数是个function?

一、为什么需要函数

有没有发现,在前面的那么多的教程当中,我们没有函数是不是也是可以写的出来的,似乎没有函数这个东西,我们变成也是可以实现的,但是,在实际的开发过程中,我们为什么需要函数呢,它到底能够给我们变成带来怎样的好处呢?

其实,函数这个东西我们可以把它想成是一个包装盒,我们没有包装盒的时候,其实也是可以把礼物送给相送的人手上的,但是,当我们用包装盒包装美化之后,我们首先会更好拿,其次,会更加的好看,更赏心悦目,当然,我们要达到的目的就是,让收到礼物的人开心,所以,我们买礼物的时候,通常都会很用心的买一个包装盒美美的包装一下。

函数,就是这么个作用,我们需要把我们写的零零散散的代码包装起来,让它更好阅读,同时也能更好的管理我们的代码。

说了这么多,那么到底如何使用函数呢?下面一一道来。

二、如何定义函数

这里,我们先把上面用很浅显的话说的函数更加正式的表达一下。函数组织好的、可重复使用的、用户实现单一或者关联功能的代码段。函数能够提高应用的模块性和代码的重复利用率。

定义函数规则

def 函数名([参数列表]):      #参数列表可选项
    函数体

举例

def printName():
    print('我是 hello world!')

printName()

注意几点

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()
  • 任何传入参数和自变量必须放在圆括号中间。
  • 函数内容以冒号起始,并且缩进。

是不是很简单,只要你学过一门编程语言,这些应该都是不值得一提。

现在我们定义好了函数,就相当于我们已经有了包装礼物的包装盒,那么我们如何用包装盒去包装礼物呢,也就是说我们如何去使用函数呢?

使用函数

规则

函数名([参数列表])

举例

  • 定义函数
def printName():
    print('我是 hello world!')
  • 调用函数
printName()

其实就是这么简单!

好了,在我们包装礼物的时候,可能我们会想收礼物的人写封信或者写点东西递交给他,这个时候,我们可能会写个小纸条啦,而函数,我们也可以传信哦!

这时候,就要用到函数参数这个概念了。

三、函数参数

函数参数就是说我们可以在定义函数的时候,在括号中定义变量,用于传给函数内部使用,已达到“传信”’的效果!

举例

def printName(name):
    print('我是:', name)

这个括号中的 name ,就是我们定义的函数参数了。

除了需要知道这个以外,我们还需要了解一个概念

实参与形参

那么什么是实参,什么是形参呢,通过下面这张图,你就知道了!

我们传信给对方的时候是不是也有很多的方式,比如,我们可以简单的拿张小纸条写写,也可以买个信封写封信。

同样,函数的参数也有一些不同的类型。

参数类型

位置实参

位置实参:函数定义中允许拥有多个形参,因此函数在调用的时候,也可能包含多个实参。向函数传递参数的方式有很多,通过实参和形参的顺序对应

关键字参数

关键字实参是传递给函数的名称-值对。直接在实参中将名称和值关联起来,因此向函数传递实参时不会混淆。函数调用使用关键字参数来确定传入的值。所以,位置可以不用对应。

# 定义函数
def printName(name, age):
    print('我是:', name)
    print('我:', age)


# 调用函数
printName(age=18, name='欧阳思海') # 名字跟形参对应,但是位置可以不对应
参数默认值

在很多语言都是有默认值这个特性的。

默认值:函数定义的时候,设置的参数是形参。那么也可以给每个形参指定一个默认值。当调用函数时,如果没有传入实参,就使用形参的默认值。如果调用的时候传入了实参,那么程序将使用传入的实参。

# 定义函数:使用默认值 age=15
def printName(name, age=15):
    print('我是:', name)
    print('我:', age)


# 调用函数
printName(age=18, name='欧阳思海')  # 名字跟形参对应,但是位置可以不对应
printName(name='欧阳思海')  # age有默认值,不赋值,默认15
不定长参数

不定长参数:你可能需要一个函数能处理比当初声明时更多的参数。

规则

def 函数名(*parameter,**parameter):
  函数体

注意:加了***的就是不定长参数。

# 定义函数
def printPara(*para, **para2):
    print(para)
    print(para2)


# 调用函数
printPara('one', 'two', 'three', four='4', five='5')

由此可知:

  • 一个*的不定长参数,会接收没有命名的实参,且会转为元祖tuple
  • 两个*的不定长参数,会接受有命名的实参,且转化为字典dictionary

以上就是函数参数的内容了。

有时候,我们把信封放在礼物中送给对方之后,可能,她直接把礼物加信息拒绝了,这时候,就返回给你了。所以,把函数参数传过去之后,并不是一定就输出结果的,有时候,还会返回。所以就有返回值

四、函数返回值

换专业点的话说:函数其实并非我们想象的总是简单的将结果直接输出,相反,函数的调用者需要函数提供一些通过函数处理过后的一个或者一组数据,只有调用者拥有了这个数据,才能够做一些其他的操作。那么这个时候,就需要函数返回给调用者数据,这个就被称之为返回值,想要在函数中把结果返回给调用者,需要在函数中使用returnreturn 就是返回值的关键词

下面,我们用一个例子直接看 return 怎么使用。

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


result = sum(1, 2)
print(result)

通过这个例子我们可以看出,通过 return 语句 这样的方式,就可以把 我们想要返回的东西返回。

然后,通过 调用函数 可以用一个变量 接收函数返回的值,以便保存使用。

看了这个例子之后,我想,我们应该知道 return 有什么作用了。

return 作用

  1. 返回结果。
  2. 退出函数,return 语句后的函数内容将不会再执行。

五、局部变量和全局变量

在编程语言中,都有叫做变量域的东西。也就是,限制我们变量在哪个地方能用,哪个地方不能用。

变量分为局部变量全局变量

局部变量:在函数内定义的变量,局部变量只能在所定义的函数内使用,在不同函数内定义的相同的变量是不会相互影响的,如果在函数 A 中定义了变量 variable,在函数 B 中也定义了变量 variable,这两个是相互不影响的。
全局变量:在函数外定义的变量,任何地方都可以使用。

举例

c = 3  # 全局变量


def sum(a, b):
    d = 5  # 局部变量
    return a + b


result = sum(1, 2)
print(result)
print(c)  # 正确,全局变量处处可以访问
print(d)  # 错误,不能访问局部变量

下面,我们需要注意一个问题,当我们需要在函数内部修改一个全局变量时,我们需要用一个关键词 global 来声明,这样我们才能够改变。

举例

c = 3  # 全局变量
print('全局变量id:', id(c))


def sum(a, b):
    global c
    c = 5  # 局部变量
    print('sum中全局变量id:', id(c))
    return a + b


def sum2(a, b):
    print('sum2中全局变量id:', id(c))
    return a + b


sum(1, 2)
print('全局变量id..:', id(c))
sum2(2, 2)

在这个例子中我们可以看到,当我们用 global c 声明之后,后面再使用变量 c 的时候,变量 c 已经改变了。

再用一个例子,当我们不用 global 声明直接修改时,后面的 变量 c 的 id的值是不会改变了。

c = 3  # 全局变量
print('全局变量id:', id(c))


def sum(a, b):
    # global c
    c = 5  # 局部变量
    print('sum中全局变量id:', id(c))
    return a + b


def sum2(a, b):
    print('sum2中全局变量id:', id(c))
    # c = 10
    return a + b


sum(1, 2)
print('全局变量id..:', id(c))
sum2(2, 2)

注:id 是用来展示变量唯一性的。

六、匿名函数

匿名函数:定义函数的过程中,没有给定名称的函数就叫做 匿名函数;Python 中使用 lambda 表达式来创建匿名函数。

规则

lambda 参数列表: 表达式

下面我们先用一个例子来看看 lambda表达式 怎么使用。

举例

res = lambda a, b: a + b

print(res(1, 2)) # 输出3

其中,a,b是参数,a + b 是执行表达式,可以是简单的表达式,也可以是函数等。

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


res = lambda a, b: sum(a, b) #执行表达式是函数

print(res(1, 2))

在前面的我们已经学过 if-else 形式了,在这里,再学习一种不一样的形式。

条件成立的内容   if 条件 else 条件不成立的内容

举例

s = lambda x, y: x if x > 2 else y
print(s(2, 4)) # 输出4

七、递归函数

递归就是子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己。

形象点说就是一个黑洞一样,一层一层的往里走,走到最后,再往回走,直到走到出发点,这就是递归的整个过程。在走的过程中,我们就可以计算。

这里只是简单的说说递归函数的简单的用法。

例如:

阶乘 1 * 2 * 3 ··· * n

'''
    阶乘
'''
def jiechen(n):
    if n == 1:
        return 1
    else:
        return n*jiechen(n-1)

print(jiechen(10))

这个例子,就是函数自己再调用函数自己。

八、高阶函数

map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。

举例说明,比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下:

现在,我们用Python代码实现:

>>> def f(x):
...     return x * x
...
>>> map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]

请注意我们定义的函数f。当我们写f时,指的是函数对象本身,当我们写f(1)时,指的是调用f函数,并传入参数1,期待返回结果1。

因此,map()传入的第一个参数是f,即函数对象本身。

map()函数这种能够接收函数作为参数的函数,称之为高阶函数(Higher-order function)。

你可能会想,不需要map()函数,写一个循环,也可以计算出结果:

L = []
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
    L.append(f(n))
print L

的确可以,但是,从上面的循环代码,能一眼看明白“把f(x)作用在list的每一个元素并把结果生成一个新的list”吗?

所以,map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数。

再看reduce的用法。reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

比方说对一个序列求和,就可以用reduce实现:

>>> def add(x, y):
...     return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。

但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场:

>>> def fn(x, y):
...     return x * 10 + y
...
>>> reduce(fn, [1, 3, 5, 7, 9])
13579

这个例子本身没多大用处,但是,如果考虑到字符串str也是一个序列,对上面的例子稍加改动,配合map(),我们就可以写出把str转换为int的函数:

>>> def fn(x, y):
...     return x * 10 + y
...
>>> def char2num(s):
...     return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
...
>>> reduce(fn, map(char2num, '13579'))
13579

整理成一个str2int的函数就是:

def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
    return reduce(fn, map(char2num, s))

还可以用lambda函数进一步简化成:

def char2num(s):
    return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]

def str2int(s):
    return reduce(lambda x,y: x*10+y, map(char2num, s))

也就是说,假设Python没有提供int()函数,你完全可以自己写一个把字符串转化为整数的函数,而且只需要几行代码!

这就是函数的基本内容了!

参考

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

推荐阅读更多精彩内容

  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,348评论 0 5
  • 这篇笔记记录的知识点:函数的基本概念自定义函数函数的几种参数 编程的三种方式:1.OOP 面向对象编程,万物皆对象...
    古月半半阅读 885评论 0 2
  • 函数只定义一次,但可能被执行或调用任意次。JS函数是参数化的,函数的定义会包括一个称为形参的标识符列表,这些参数在...
    PySong阅读 467评论 0 0
  • 函数只定义一次,但可能被执行或调用任意次。JS函数是参数化的,函数的定义会包括一个称为形参的标识符列表,这些参数在...
    PySong阅读 820评论 0 0
  • 车流不通环山路,浮冰塌陷融流沙。 黄河一泄至云海,浑水翻涌推前浪。 击石拍壁白烟散,鸣雷闪电狂涛吼。 壶口瀑布非虚...
    _文刀人青_阅读 788评论 0 0