函数


函数

一、函数基础知识

1、概念讲解

当我们在编写代码实现功能的时候,比如验证用户的登陆状态(确认用户的用户名和密码),一些情况下需要反复验证,这种时候就会反复套用一段一样的代码来检验。仔细想想这些地方其实进行了重复操作,因此我们引入了函数进行简化。这就相当于一个工人去干活,在最初的时候需要一次次的制造工具再去干活,后来他发现这挺蠢的。就做了工具之后保存好,每次干活的时候拿出来使用一下就可以快速完成工作了。

2、语法结构

def 函数名(参数(可以有多个,后续会讲):
	'''函数注释(解释函数功能)'''
	函数体代码
	return 返回值
1.def
	定义函数的关键字
2.函数名
	命名等同于变量名,这里我们需要尽量做到见名知意,方便在使用的时候理解它的作用
3.参数
	可有可无,主要是在使用函数的时候规定要不要外界传数据进来
4.函数注释
	类似于工具说明书
5.函数体代码
	是整个函数的核心,主要取决于程序员的编写
6.return
	使用函数之后可以返回给使用者的数据,可有可无。
    当我们给返回值的时候可以写多个,甚至是不同数据类型的多个数据值,他们会被封装到一个元组中一次性输出
    当我们使用return的时候,意味着函数运行到这里就停止了,如果下方还有代码将不会运行。

image

3、函数的定义与调用

1.函数在定义阶段只检测语法,不执行代码。通常在编写代码的时候我们先定义这个函数然后用pass完善结构,这个状态下的函数也叫做空函数。等到需要填入内容的时候再填入内容替换pass。

def func():
	pass

image

2.函数在调用阶段才会执行函数体代码

func()

3.函数必须先定义后调用,如果不定义就先调用会报错
4.函数定义使用关键字def

5.函数调用使用>>>:函数名加括号
如果有参数则需要在括号内按照相应的规则传递参数(后续详细讲解)

4、函数的分类

1.空函数
	函数体代码为空 使用的pass或者...补全的
 	空函数主要用于项目前期的功能框架搭建
 	 def register():
        """注册功能"""
        pass
2.无参函数
	 定义函数的时候括号内没有参数
	 def index():
        print('from index function')
3.有参函数
	定义函数的时候括号内写参数 调用函数的时候括号传参数
 	def func(a):
    	  print(a)

image

5、函数的返回值

1.什么是返回值
	调用函数之后返回给调用者的结果
2.如何获取返回值
	变量名 赋值符号 函数的调用
 	res = func()  # 先执行func函数 然后将返回值赋值给变量res
3.函数返回值的多种情况
	3.1.函数体代码中没有return关键字 默认返回None
 	3.2.函数体代码有return 如果后面没有写任何东西还是返回None
 	3.3.函数体代码有return 后面写什么就返回什么
 	3.4.函数体代码有return并且后面有多个数据值 则自动组织成元组返回
 	3.5.函数体代码遇到return会立刻结束

image

二、函数参数

形式参数
	在函数定义阶段括号内填写的参数 简称'形参'
实际参数
	在函数调用阶段括号内填写的参数 简称'实参'
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
形参与实参的关系
	形参类似于变量名 在函数定义阶段可以随便写 最好见名知意
	def register(name,pwd):
		pass
	
	实参类似于数据值 在函数调用阶段与形参临时绑定 函数运行结束立刻断开
	register('jason',123)   形参name与jason绑定 形参pwd与123绑定
"""
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

image

一下每一大类参数都分为形参和实参两种情况:

1、位置参数

位置形参

函数定义阶段括号内从左往右依次填写的变量名

def func1(a, b, c):pass

ps:当定义函数的时候,如果函数体代码足够简短并且只有一行可以不用换行直接跟在后面。

位置实参

函数调用阶段括号内从左往右依次填写的数据值

func1(1, 2, 3)

调用函数时的注意事项:

1、当我们在调用函数的时候,也需要在括号内加入对应的参数,并且这种情况下参数个数需要一样。

2、当我们给函数传参数的时候需要遵循一定的规律,把简短的放在前面,长的放在后面,简单的放在前面,复杂的放在后面。

3、在给函数传参数的时候也可以用关键字进行传参,由于关键字参数比位置参数要长,要复杂,所以使用的时候需要把它放在后面。

4、当我们在使用多种形式的参数给函数传参数的时候需要仔细判断,如果出现给一个形参传了两个参数会报错(不能多次赋值)。

5、调用函数的时候也可以使用变量来传参。

def func1(a, b):
    print(a, b)


# func1(1, 2)  # 按照位置一一对应传值
# func1(1)  # 少一个不行
# func1(1, 2, 3)  # 多一个也不行
# func1(b=1, a=2)  # 关键字传参(指名道姓的传)
# func1(b=1, 2)  # 关键字传参一定要跟在位置传参的后面  报错
# func1(2, b=1)  # 可以
# func1(1, a=2, b=3)  # 同一个形参在调用的时候不能多次赋值
name = 'jason'
pwd = 123
# func1(name, pwd)  # 实参没有固定的定义 可以传数据值 也可以传绑定了数据值的变量名
func1(a=name, b=pwd)  # 实参没有固定的定义 可以传数据值 也可以传绑定了数据值的变量名

2、默认参数(关键字参数)

所谓默认参数,本质上就是关键字参数,我们在定义的时候提前准备好一个默认的值,之后在调用的时候就可以选择不给参数,使用默认值。

关键字形参

当函数定义的时候,我们直接在参数中加入关键字,这个时候如果有别的位置形参,也要遵循短的简单的在前面,长的复杂的在后面的规律

def register(name, age, gender='male'):
    print(f"""
    --------学员信息----------
    姓名:{name}
    年龄:{age}
    性别:{gender}
    -------------------------
    """)
register('jason', 18) # 输出的时候使用默认参数male
register('kevin', 28) # 输出的时候使用默认参数male
register('lili', 28, 'female') # 输出的时候使用实参输入的female
register('lili', 28, gender='female') # 输出的时候使用实参输入的female

关键字实参

关键字实参其实在将位置实参的时候一起讲解了,实际使用时候的规律可以参考上面的知识点。

3、可变长形参(可变长度的形参)

在我们定义函数的时候,如果想使用一个形参来接收传参时多余的一些参数,使函数不会在传参阶段出现报错,就可以使用可变长形参来接收多余的数据。下面我们介绍两种可变长形参:

1、在形参前面加一个*号

当我们给前面有一个''号的形参传多个位置参数的时候,这个''号会把所有的参数都接收然后放到一个元组中,再传给后面跟着的那个形参,我们通过打印就可以看到接收后的结果:

# def func1(*a):
#     print(a)
# func1()  # ()
# func1(1)  # (1,)
# func1(1,2)  # (1, 2)

# def func2(b, *a):
#     print(a, b)
# func2()  # 函数至少需要一个参数给到b
# func2(1)  # () 1
# func2(1, 2, 3, 4)  # (2, 3, 4) 1

ps:这里需要注意,如果函数的形参没有按照规定做到简单的短的放在前面,把可变长形参放到了前面,那么所有的位置参数都会被视为没用的数据被接收,其他后面的形参会接收不到实参,从而报错。

2、在形参前面加两个*号

两个*号跟在前面的形参表示接收所有多余的关键字参数,然后把这些关键字放入字典中,赋值给绑定的那个形参变量名。

# def func3(**k):
#     print(k)
# func3()  # {}
# func3(a=1)  # {'a': 1}
# func3(a=1, b=2, c=3)  # {'a': 1, 'b': 2, 'c': 3}

# def func4(a, **k):
#     print(a, k)


# func4()  # 函数至少需要一个参数给到a
# func4(a=1)  # 1 {}
# func4(a=1, b=2, c=3)  # 1 {'b': 2, 'c': 3}
# func4(a=1, b=2, c=3, x='jason', y='kevin')  # 1 {'b': 2, 'c': 3, 'x': 'jason', 'y': 'kevin'}

由于两种形式的形参功能强大,使用频率很高,所以我们推荐使用以下两个变量名,方便判断:

*args
**kwargs

两者形式结合使用展示:

# def func5(*a, **k):
#     print(a, k)
# func5()  # () {}
# func5(1, 2, 3)  # (1, 2, 3) {}
# func5(a=1, b=2, c=3)  # () {'a': 1, 'b': 2, 'c': 3}
# func5(1, 2, 3, a=1, b=2, c=3)  # (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}


# def func5(n, *a, **k):
#     print(a, k)


# func5()  # 函数至少需要一个参数给到n
# func5(1, 2, 3)  # (2, 3) {}
# func5(111,a=1, b=2, c=3)  # () {'a': 1, 'b': 2, 'c': 3}
# func5(n=111,a=1, b=2, c=3)  # () {'a': 1, 'b': 2, 'c': 3}
# func5(a=1, b=2, c=3, n=111)  # () {'a': 1, 'b': 2, 'c': 3}
# func5(1, 2, 3, a=1, b=2, c=3)  # (2, 3) {'a': 1, 'b': 2, 'c': 3}

4、可变长实参(可变长度的实参)

在可变长形参中我们得知一个号和两个号在形参中的作用,这两个符号在实参中也有两种不同的作用:

单个*号的作用:

在我们调用函数写入实参的时候,如果想把一个列表中的所有数据都传进去,我们可以直接在括号内写上列表的变量名然后在前面加个号,这样就可以把列表中的一个个值分别传入函数中。相当于使用for循环遍历数据按照位置参数传参给函数。当然号不仅仅列表能用字典元组字符串也是适用的。但是字典只能取到key。

# def index(a, b, c):
#     print(a, b, c)
# l1 = [11, 22, 33]
# t1 = (33, 22, 11)
# s1 = 'tom'
# se = {123, 321, 222}
# d1 = {'username': 'jason', 'pwd': 123, 'age': 18}
'''将列表中三个数据值取出来传给函数的三个形参'''
# index(l1[0], l1[1], l1[2])
# index(*l1)  # index(11, 22, 33)
# index(*t1)  # index(33, 22, 11)
# index(*s1)  # index('t','o','m')
# index(*se)  # index(321 123 222)
# index(*d1)  # index('username','pwd','age')

两个*号的作用:

两个号的作用范围比一个号少,只能被字典使用,当我们使用的时候,可以把字典内的一个个值打散成关键字参数直接传入函数中。

# def index(username, pwd, age):
#     print(username, pwd, age)
# d1 = {'username': 'jason', 'pwd': 123, 'age': 18}
# index(username=d1.get('username'), pwd=d1.get('pwd'), age=d1.get('age'))
# index(**d1)  # index(username='jason',pwd=123,age=18)

5、命名关键字参数(了解)

这里讲的是一种特殊情况下的关键字形参,先看例子:

def index(name,*args,gender='male',**kwargs):
    print(name, args, gender, kwargs)
    
# index('jason',1,2,3,4,a=1,b=2)
index('jason', 1, 2, 3, 4, 'female', b=2)

我们可以看到由于长的复杂的需要放到后面,关键字形参需要安排到可变长形参中接收多余位置形参的参数的后面,接收多余关键字形参的参数的前面。当我们调用函数的时候就必须在写实参的时候用上关键字实参来表述,否则的话就会被判定成多余的位置实参被args形参直接接收走。

在我们编写代码的时候要尽量避免这种复杂的情况。

三、函数名的多种用法

函数名称其实就是绑定了一个内存地址的变量名,只不过它的内部放的不是数据值而是一堆代码,我们可以通过不同的形式调用他们,最后只需要在末尾加上一个括号。下面我们介绍函数的四种用法:

1、函数名可以当作变量名赋值

我们可以把函数名跟别的变量名绑定关系,这样通过调用这个变量名就等于调用了函数,调用的时候在变量名后面需要加括号。

def index():pass
res = index
res()

2、函数名可以当作函数的参数

当我们在使用函数的时候,可以把别的函数的函数名当成参数传到函数中去,如果那个函数有定义相关的内容就可以执行对应的功能。

def index():
    print('from index')
def func(a):
	print(a)
	a()
func(index)

3、函数名可以当作函数的返回值

我们还可以把函数当作其他函数或函数本身的返回值,这样当我们调用函数后就会发现变量名绑定的结果时返回的那个函数的名称。

def index():
    print('from index')

def func():
	print('from func')
    return index
res = func()
print(res)  # 会返回一串文字,表示这是func函数
res()

def index():
	print('from index')
def func():
	print('from func')
	return func

res = index()
print(res)  # 会返回一串文字,表示这是index函数
res()

4、函数名还可以当作存储数据的容器中的数据

这里我们举例,函数的名称被放到字典中形成了一种存储数据的容器,这时候我们就不需要一直使用if方法创建很多分支来达到相应的功能了。直接根据对应的功能选择对应的字典的key,然后根据key调用对应的函数。

	def register():
    	print('注册功能')


	def login():
    	print('登录功能')


	def withdraw():
    	print('提现功能')


	def transfer():
    	print('转账功能')


	def shopping():
    	print('购物功能')


    # 定义功能编号与功能的对应关系
    func_dict = {
        '1': register,
        '2': login,
        '3': withdraw,
        '4': transfer,
        '5': shopping
    }

    while True:
        print("""
        1.注册功能
        2.登录功能
        3.提现功能
        4.转账功能
        5.购物功能
        """)
        choice = input('>>>:').strip()
        if choice in func_dict:
            func_name = func_dict.get(choice)
            func_name()
        else:
            print('功能编号不存在')
        # if choice == '1':
        #     register()
        # elif choice == '2':
        #     login()
        # elif choice == '3':
        #     withdraw()
        # elif choice == '4':
        #     transfer()
        # elif choice == '5':
        #     shopping()
        # else:
        #     print('去你妹的 终于写完了')


posted @ 2022-10-16 19:11  致丶幻  阅读(79)  评论(0编辑  收藏  举报