第 6 章. 函数与代码复用

1.函数的概念

函数是一段具有特定功能的,可重用的语句组,用函数名来表示并通过函数名进行完成功能调用。

函数也可以看作是一段具有名字的子程序,可以在需要的地方调用执行,不需要再每个执行地方重复编写这些语句。每次使用函数可以提供不同的参数作为输入,以实现对不同数据的处理;函数执行后,还可以反馈相应的处理结果、

函数是一种功能抽象。

2.python 中函数的定义

python定义一个函数使用 def关键字,语法形式如下:

def<函数名>(<参数列表>):
    <函数体>
    return<返回值列表>

实例:生日歌

过生日时要为朋友唱生日歌,歌词为:

Happy birthday to you!
Happy birthday to you!
Happy birthday,dear<名字>
Happy birthday to you!

编写程序为MikeLily输出生日歌。最简单的方式是重复使用print()语句

print('Happy birthday to you!')
print('Happy birthday to you!')
print('Happy birthday,dear Mike!')
print('Happy birthday to you!')

print('Happy birthday to you!')
print('Happy birthday to you!')
print('Happy birthday,dear Lily!')
print('Happy birthday to you!')
Happy birthday to you!
Happy birthday to you!
Happy birthday,dear Mike!
Happy birthday to you!
Happy birthday to you!
Happy birthday to you!
Happy birthday,dear Lily!
Happy birthday to you!

已函数的方式:

def happy():
    print('Happy birthday to you!')
    
def happy_birthday(name):
    happy()
    happy()
    print("Happy birthday,dear {}!".format(name))
    happy()

# 调用函数
happy_birthday('Mike')
print()
happy_birthday('Lily')
Happy birthday to you!
Happy birthday to you!
Happy birthday,dear Mike!
Happy birthday to you!

Happy birthday to you!
Happy birthday to you!
Happy birthday,dear Lily!
Happy birthday to you!

看起来和上面的直接print还多个几行代码,但是考虑如果给100个人唱生日歌的情况就非常简洁了。

3.函数的调用过程

程序调用一个函数需要执行以下四个步骤:

  1. 调用程序在调用处暂停执行
  2. 在调用时将实参赋值给函数的形参
  3. 执行函数体语句
  4. 函数调用结束给出返回值,程序回到调用前的暂停处继续执行。

4.函数的参数

定义函数时()里的参数叫形参(形式参数),它只是一个变量名,供函数体中的代码调用。

函数调用时,传入()里的参数叫实参(实际参数),它是实际的数据,会传递给形参,供函数体执行。

4.1 形参

定义函数时,形参根据功能不同,可以定义几种类型。

4.11 必须参数

在定义函数时,如果要求调用者必须传递实参给这个形参,它就是必须参数。

直接定义在函数名后的()中的形参就是必须参数。

例如上面的happy_birthday函数中的name

案例:

定义一个函数接收两个数,然后打印它们的和

def add(x, y):
    print(x+y)
add(1)   #调用时必须传递实参给必须参数,否则报错
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_16432/2895855552.py in <module>
----> 1 add(1)   #调用时必须传递实参给必须参数,否则报错

TypeError: add() missing 1 required positional argument: 'y'
class abc:
    """
    这是个。。。
    """
a = abc()
print(type(a))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_5240/4255954294.py in <module>
----> 1 a = abc()
      2 print(type(a))

NameError: name 'abc' is not defined

4.1.2 默认参数

在定义函数时,某些形参有可能在调用时不用接收实参,这种情况可以定义为默认参数。
在函数名后 ()中,以参数名=默认值的形式定义的形参就是默认参数。
注意:默认参数必须定义在必须参数的后面
案例:
定义一个函数,它接收两个参数contenttimes
content是函数要打印的内容
times是函数打印的次数,如果不传递times默认打印1次

# 定义
def my_print(content, times=1):
    for i in range(times):
        print(content)
# 调用
my_print('happy birthday!')
my_print('happy birthday!', 2)
happy birthday!
happy birthday!
happy birthday!

调用函数时传递实参给默认形参会覆盖默认值

4.1.3 不定参数

在定义函数时,不确定在调用时会传递多个实参时,可以定义不定参数。
不定参数根据传递实参的不同(详见4.2实参)有分为两种。

位置不定参
在函数名后的()中,在形参前加*号可以定义位置不定参,通常它会定义为*args
它用来接收函数调用时,以位置参数传递过来的超过形参数量的多余的实参。
注意:不定参必须定义在默认参数后面
位置不定参数会将所有多余的位置实参创建成元组。

def func(a, *args):
    print(args,type(args))

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

案例:
定义一个函数,接收2个以上的数,打印它们的和。

def add(x,y,*args):
    x += y
    for i in args:
        x += i
    print(x)
add(1,2,3,4,5)
15

关键字不定参
在函数名后的()中,在形参前加**号可以定义关键字不定参,通常它会定义为**kwargs
它用来接收函数调用时,以关键字参数传递过来的超过形参数量的多余的实参。
注意:不定参必须定义在默认参数后面
关键字不定参数会将所有多余的关键字实参创建成字典。

def func(a, **kwargs):
    print(kwargs, type(kwargs))

func(a=1,b=2,c=3)
{'b': 2, 'c': 3} <class 'dict'>

4.2 实参

调用函数并传递实参有两种方式。

4.2.1 位置参数

调用函数时,传递实参时默认会按照形参的位置一一对应,这种实参传递叫做位置参数。
案例:
定义一个函数实现打印一个数的n次幂。

def my_power(x, y):
    print(x ** y)

my_power(2,3)
my_power(3,2)
8
9

4.2.2 关键字参数

调用函数时,传递实参时以形参名=实参的形式传递参数,叫做关键字参数。
这是不用考虑参数的位置
注意:关键字参数必须写在位置参数后面。
案例:
使用关键字参数调用上面的案例

my_power(x=2, y=3)
my_power(y=2, x=3)
my_power(2, y=3)
8
9
8
my_power(x=2, 3)   # 关键字参数必须写在位置参数后面。
  File "C:\Users\ren_zlf\AppData\Local\Temp/ipykernel_5240/2386097555.py", line 1
    my_power(x=2, 3)   # 关键字参数必须写在位置参数后面。
                   ^
SyntaxError: positional argument follows keyword argument

4.2.3 *, **在传递实参时的用法

*解包
在传递实参时,可以通过*对迭代对象进行解包。

def fun(a, b, *args):
    print(a, b, args)
ls = [1,2,3,4,5,6]
fun(*ls)
1 2 (3, 4, 5, 6)

**解包
在传递实参时,可以通过**对字典对象进行解包。

def fun(a, b, **kwargs):
    print(a, b, kwargs)
b = {'a':1,'b':2,'c':3,'d':4}
fun(**b)
1 2 {'c': 3, 'd': 4}

4.3 返回值

函数还有一个很重要的功能就是返回结果。
python中使用return关键字来退出函数,返回到函数被调用的地方继续往下执行。
return可以将0个,1个,多个函数运算完的结果返回给函数被调用处的变量、
函数可以没有返回值,也就是说函数中可以没有return语句,这时函数返回None,例如上面我们定义的那些函数。
return会将多个返回值以元组的形式返回。
案例:
定义一个函数接收2个或多个数值,并返回它们的和。

def add(x, y, *args):
    x += y
    for i in args:
        x += i
    return x

res = add(1,2,3,4)
print(res)
10

5.lambda 函数

简单来说,lambda函数用来定义简单的,能够在一行内表示的函数。
语法格式如下:

lambda arg1,arg2,...:expression
f = lambda x,y : x + y
res = f(1,2)
print(res)
3

lambda函数一般不会直接定义,通常是作为参数传递给其他函数作为参数使用。

6.变量作用域

python中一个变量能够被访问的范围叫做作用域。根据作用域的大小简单的分为全局变量和局部变量。

6.1 全局变量

python是解释性编辑语言,解释器在运行一个python程序时会在计算机内存中申请一块内存用来运行这个程序。全局变量在这块内存空间中都可以访问和修改。
直接定义在函数外的变量就是全局变量,在程序运行的全过程有效。

6.2 局部变量

定义在函数里,的变量就是局部变量,它只在它定义的函数里起作用,一但函数执行完毕它就不存在了。
案例:

a = 1 # 全局变量

def fun():
    print(a)   
fun()
1

上面的案例说明全局变量能够在函数里访问

def fun():
    b1 = 2  # 局部变量
    print(b1)

fun()
print(b1)
2
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_5240/3546466530.py in <module>
      4 
      5 fun()
----> 6 print(b1)

NameError: name 'b1' is not defined

上面的案例说明局部变量再函数外部不能直接访问。

a = 1
def fun():
    a += 1
    print(a)  # 尝试直接再函数内部修改全局变量
fun()
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_5240/3731582065.py in <module>
      3     a += 1
      4     print(a)  # 尝试直接再函数内部修改全局变量
----> 5 fun()

~\AppData\Local\Temp/ipykernel_5240/3731582065.py in fun()
      1 a = 1
      2 def fun():
----> 3     a += 1
      4     print(a)  # 尝试直接再函数内部修改全局变量
      5 fun()

UnboundLocalError: local variable 'a' referenced before assignment

上面的案例说明再函数内部不能直接修改全局变量(不可变数据类型)

可变数据类型的修改不受影响,所以可变类型的全局变量再使用的过程中需要格外的注意

a = [1,2]
def func():
    a[0] = 2
    print(a)
func()
print(a)
[2, 2]
[2, 2]

6.2 global 关键字

有时候需要再函数内部修改全局变量。
使用globals关键字可以再函数内部修改全局变量
案例:

a = 1 # 全局变量

def fun():
    global a # 申明a 是全局变量
    a += 1
fun()
print(a)
2
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容