python---函数及参数

函数介绍

  • 函数的定义:

    • def 函数名(参数):

      函数体

      return 返回值

  • 函数的调用:函数名(参数)

# 函数: 将特定的功能所对应的代码片段进行打包,封存在一个函数内,如果我们想要重复使用该功能,就直接调用函数即可
# 函数的作用: 提高代码复用率,提高开发效率,易于维护

'''
函数定义的格式:
def 函数名(参数1, 参数2,参数3....):
  函数体
  return 返回值

函数调用的格式:
函数名(参数1,参数2,参数3.....)

# 函数名:绝大多数函数都有函数名,没有函数名的函数不能被复用
# 参数:为了让函数灵活性更高,更容易被复用,会动态对函数进行传值,传递的值可以在函数体内部进行使用
# 函数体: 特定功能的代码,写在函数内部,调用函数时可全部执行
# 返回值: 写在return之后,将函数内部计算或运行得到的数据传递到函数体外部
'''

# 定义的时候可以不传参,如果不传调用的时候也不用传参
def run():
   print('我跑的老快了,没人追的上我,钱包在我手里')
   print('我跑的老快了,没人追的上我,手机在我手里')
   print('我跑的老快了,没人追的上我,女朋友在我手里')

# 调用时可以将函数内的代码全部执行一遍
run()
run()
  • 函数的调用顺序:从上到下依次执行,先键函数名保存到函数列表中,调用的时候去类表中查询,如果存在则调用其中的代码,如果不存在则报错

# NameError: name 'sing' is not defined
# 函数需要先定义后调用否则会报错
# sing()
# 定义一个唱歌方法
def sing():
   print('我再唱青藏高原')
# 定义一个跳舞方法
def dance():
   print('我再跳广场舞')

sing()
dance()

# 执行顺序: 先讲所有函数的函数名执行一遍将其储存到缓存中的方法列表中,后续调用函数时去方法列表中查询,如果函数名存在,则调用函数内部的代码,如果函数名不存在将报错

函数参数

  • 函数的参数可以增加代码的灵活性

    • 在定义时传入的参数是形参,只能在函数体内部使用

    • 在调用的时候传入的参数是实参,可以传入到函数体内部被形参接收

# 定义一个eat方法,通过传入不同的参数,可以输出不同的生物吃不同的食物


def eat_cat():
   print('猫吃鱼')

def eat_dog():
   print('狗吃肉')

def eat_person():
   print('人吃藕')

# 上述函数定义方法不太方便,因为如果有更多的生物去吃不同的东西,就要重复书写函数不利于函数的复用

# 改进 >> 传参
# 通过传入参数,可以控制函数体内部的执行结果发生变化,让函数更加灵活
def eat(who, food):  # 在定义时传入的参数叫做形参,只能在函数体内部使用
   print(f'{who}吃{food}')

# 在调用的时候传入的参数叫做实参,会传入到函数内部被形参接收
eat('猫', '🐟')
eat('狗', '肉')
eat('人', '藕')

# TypeError: eat() missing 1 required positional argument: 'food'
# 进行传值时需要保证传参数量满足要求,否则会报错
# eat('人')

函数返回值

  • 1.返回值是将函数内计算或运行的结果返回到函数外部调用位置,参与计算或运行

  • 2.函数可以不写返回值或者只写一个return不写返回值内容,都会默认返回一个None

  • 3.return后将会立即跳出函数,如果在retrun后仍有代码,则不会被执行

  • 4.return只能返回一个元素,如果想返回多个元素需要使用容器类型

# 返回值:将函数体内部运行或计算得到的数据传递到函数体外部

# def sum(a, b):
#     print(a + b)
#
#
# sum(1, 2)


# 思考?如果我们想在函数体外部使用这个结果进行二次运算我应该怎么做?
# NameError: name 'a' is not defined a, b 是形参,只能在函数体内部使用
# print(a + b)

# 如果我们想将数据传递出来可以使用return
def sum1(a, b):
   return a + b


print(sum1(1, 3))  # 当函数执行完毕,函数调用位置就替换为函数的返回值
# 返回的数据可以参与计算
print(sum1(1, 3) + 12)
# 注意:返回值内容不会自动打印到控制台,将数据返回后如果想要查看数据需要手动打印或者debug调试


# 如果没有return 那么就没有返回值么?
list1 = [1, 2]
# 因为此处,append方法,没有返回值,默认返回None
print(list1.append(3))  # None


def eat():
   print('猫吃鱼,狗吃肉,奥特曼吃小怪兽')


# 如果没有书写返回值,则返回值为None
print(eat())  # None


# 如果只写了return 没有写返回值内容会怎么样? None

def sum1(a, b):
   print(a + b)
   return


print(sum1(1, 2))  # None


# return 执行后会跳出函数,return之后的所有代码将不会继续执行
# 在函数中可以有多个return 但是只能执行一个
def function():
   print('hello python')
   return
   return
   # 同一分支中,在return之后的所有代码不会被执行
   print('hello bigdata')


function()


# 返回值只能是一个么? 可以返回多个返回值么?
# 返回值只能是一个元素,如果要返回多个值只能通过容器类型进行打包
def function1():
   return 1, 2, 3, 4
print(function1())  # (1, 2, 3, 4)

# 结论:
'''
1.返回值是将函数内计算或运行的结果返回到函数外部调用位置,参与计算或运行
2.函数可以不写返回值或者只写一个return不写返回值内容,都会默认返回一个None
3.return后将会立即跳出函数,如果在retrun后仍有代码,则不会被执行
4.return只能返回一个元素,如果想返回多个元素需要使用容器类型
'''

函数的嵌套

  • 在一个函数体内部嵌套了另一个函数的调用

# 函数的嵌套,就是在一个函数的内部嵌套了另一个函数的调用

def function2():
   print('我是func2-----')
   function1()
   print('我是func2-----')

def function1():
   print('func1执行开始')
   print('func1执行结束')


# def function2():
#     print('我是func2-----')
#     function1()
#     print('我是func2-----')

function2()

# 执行顺序,只要函数在调用之前被定义即可,定义函数的顺序不做规定

局部变量和全局变量

  • 局部变量就是在函数体内部进行定义函数体外部无法调用的变量

  • 全局变量就是在函数体外部,一般在文件顶格处书写,函数体内外都可以使用的变量

  • if 和for结构中的控制语句中定义的变量都是全局变量

# 全局变量就是在函数体外部书写的一般要在文件内顶格书写,在函数体内部外部都可以调用的变量
a = 1
b = 2


def sum1():
   # 函数体内部可以使用
   print(a + b)


sum1()
# 函数体外部也可以使用
print(a)
print(b)

# for 循环中, if 分支中创建的变量是全局变量还是局部变量呢? 全局变量
# for i in range(10):
#     pass
#
# print(i)
#
# if True:
#     c = 1
# print(c)

gloal

  • global能声明我们当前使用的变量是全局变量

  • LEGB原则

    • L:在函数体内部查找

    • E:在外层函数中查找

    • G:在全局变量中查找

    • B:在内置变量中查找

# global  全局  :作用就是声明我要使用的这个变量是全局变量

# 如果要在函数体内修改全局变量,就要使用global
a = 100

# 此处,使用a=1相当于再函数体内定义了一个局部变量,并没有修改全局变量的值
# def func1():
#     a = 1
# 如果想要在函数体内修改全局变量就要使用global
# def func1():
#     global a
#     a = 1
#
# func1()
# print(a)

# 扩展: 在Python中所有的变量查询遵循legb原则
# 调用变量时的查询顺序
'''
L:local :首先在函数体内部查询
E:edge :在外部函数中查询
g:global:在全局变量中查询
b:built-in:在系统内置变量中查询
'''
def func1():
   # L:我们再调用变量时,先在函数体内部查找
   a = 1
   print(a)
func1()

def out_func():
   # E: 如果当前函数中没有此变量,我们将在外部函数中查找
   a = 2
   def in_func():
       print(a)
   in_func()

out_func()

def func2():
   # 如果函数体内部和外部函数中都没有该变量,则去全局变量中查找
   print(a)

func2()

# 当这个函数在函数体内部,外部函数中,全局变量中都不存在时, 则去内置变量中查找
print(__name__) # __main__


def func3():
   # a = a + 10
   # 首先用a + 10 进行计算,根据legb原则先从函数体内部查找,查找后发现a 在函数体内部定义,但是在调用时未定义则报错
   # a += 10
   # print(a)
   a = 1

def func4():
   # SyntaxError: name 'a' is assigned to before global declaration
   # 如果要对全局变量进行修改,则先对变量进行global修饰,在修改,否则报错
   a = 15
   # global a
func4()
print(a)

# 能否在函数体内部创建全局变量 可以 只要用global修饰即可
def func5():
   global num1
   num1 = 105

func5()
print(num1)

函数参数进阶

  • 位置参数:直接书写参数名,在传值时顺序传值,调用时既不能多传参,也不能少传参(形参)

  • 关键字参数:使用”参数名 = 值“的形式进行传参(实参)

    • 可以不按顺序赋值

    • 必须在顺序赋值之后完成赋值

  • 缺省参数:在定义函数时,给参数一个默认值,如果调用时,不给其传参,则使用默认值,如果传参,则使用传入的值

# 位置参数:按照位置顺序进行赋值的参数(形参)

def func(a, b, c, d):
   print(a)
   print(b)
   print(c)
   print(d)


# TypeError: func() missing 1 required positional argument: 'd'
# 如果有位置参数没有被赋值,则报错
# func(1, 2, 3)

# TypeError: func() takes 4 positional arguments but 5 were given
# 如果位置参数传参过多也会报错
# func(1, 2, 3, 4, 5)
# 结论:位置参数在使用时需要保证每个参数都被赋值,且不要重复赋值或赋多个值
# 在为位置参数顺序赋值时,所有的参数按序赋值给每个位置参数
func(1, 2, 3, 4)


# 关键字参数 : 关键字参数就是通过"参数名 = 值"的形式进行赋值的参数(实参)

def func(a, b, c, d):
   print(a)
   print(b)
   print(c)
   print(d)

# 使用关键字参数,不需要按照顺序赋值,只要参数名称正确即可
func(d=4, a=1, c=3, b=2)


# 使用参数=值的形式赋值,就是关键字参数
# func(a=1, b=2, c=3, d=4)
# TypeError: func() got an unexpected keyword argument 'f'
# 使用关键字参数赋值时,要注意所使用的参数是否存在,最好是提示出来在用
# func(f=1, b=2, c=3, d=4)
# 注意:使用关键字参数要防止重复赋值
# TypeError: func() got multiple values for argument 'a'
# func(1,2,3,a=5)
# 一般情况下,关键字参数都是给默认参数(缺省参数)赋值的

# 缺省参数:就是在定义时给参数一个默认值,如果参数没有赋值,则使用默认值
def func(a, b, c, d=10):
   print(a)
   print(b)
   print(c)
   print(d)


# 不给缺省参数传值则使用默认值
# func(1, 2, 3)
# 给缺省参数传值则使用传入的值
# func(1, 2, 3, 4)

# 一般使用关键字参数给缺省参数赋值
# func(1, 2, 3, d=12)
# 关键字参数赋值,不能在顺序赋值之前
# func(d=12,1, 2, 3)

不定长参数

  • 位置不定长参数(*args):多余的位置参数,可以被args接收,并且打包为一个元组,保存在args当中。

# 不定长参数主要就是在定义函数时,不确定参数的个数时即可进行不定长参数的书写

'''
位置不定长参数的定义格式:
def 参数名(*args):
  函数体
'''


# def func(*args):
#     print(*args) # 相当于书写内容为 print(1,2,3)
#
#
# func(1, 2, 3)
# print(1, 2, 3)

# args变量到底内部是什么样子的?
# def func(*args):
#     return args

# 数据传入函数内部时,将传入的多个数据进行打包,转换为一个元组,被args接收.并且在函数体内部可以使用该元组参与运算
# print(func(1, 2, 3)) # (1, 2, 3)


# 案例:
# 输入不确定数量的多个值,判断其中的最大值

def max1(*args):
   max_num = args[0]  # 如果max_num = 0 这个时候我们所有值都没负的时候会判断出错
   for i in args:
       if i > max_num:
           max_num = i
   return max_num


print(max1(1, 4, 5, 3, 6, 12, 3))

# 如果输入的数值全部为负呢?
print(max1(-1, -2, -5))
  • 关键字不定长参数(**kwargs):将多余的关键字 参数,打包为一个字典,保存在kwargs当中

# 关键字不定长参数,可以接收多个未定义参数的关键字赋值

'''
关键字不定长参数的格式:
def 函数名(**kwargs):
  函数体
'''


# TypeError: 'a' is an invalid keyword argument for print()
# def func(**kwargs):
#     print(**kwargs) # 相当于给print输入了多个关键字参数 print(a=1, b=2, c=3)
#
#
# func(a=1, b=2, c=3)

# 使用**kwargs可以将关键字参数进行传递
# def func(**kwargs):
#     print(1, 2, **kwargs) # 相当于print(1, 2, sep='&', end='a')
#
#
# func(sep='&', end='a')

# kwargs 内部到底是什么存储结构呢?
def func(**kwargs):
   # kwargs 在从传参之后,会将实参位置的所有未定义参数的关键字参数转换为字典的键值对,保存在kwargs当中
   print(kwargs)  # {'a': 1, 'b': 2, 'c': 3}


func(a=1, b=2, c=3)


# 案例:
# 使用创建一个函数可以保存学员的全部信息,并将其储存到字典当中

def student_info(**kwargs):
   print(f'学员信息为:{kwargs}')


student_info(name='xiaoming', age=18, gender='男')

 

函数定义和调用时各类参数的排布顺序

  • 形参: 位置参数》》位置不定长参数》》缺省参数》》关键字不定长参数

  • 实参:顺序赋值》》关键字参数赋值

  • 在开发中除非有特殊需求,一般参数种类不超过三种,参数个数不超过5个,如果种类或数量太多,会造成我们开发中沟通成本加大

# 在定义函数时:位置参数,缺省参数,位置不定长参数,关键字不定长参数  到底在定义时怎么排列呢?
# 调用函数时:顺序赋值, 关键字赋值 调用时的传参顺序是什么样的呢?


# 定义函数时:形参

# 位置参数和缺省参数的位置关系:
# def func1(a, b, c=10):
#     print(a)
#     print(b)
#     print(c)
# 缺省参数c 能否放到a,b之前或之间
# SyntaxError: non-default argument follows default argument
# 有默认值的参数只能放到没有默认值的参数之后,不能前置
# def func1(c=10,a, b ):
#     print(a)
#     print(b)
#     print(c)
#
# # 赋值时可以不给c传参因为其有默认值
# func1(1, 2)

# 结论: 在定义函数时,位置参数在缺省参数之前

# 位置参数,缺省参数,位置不定长参数之间的位置关系
# 顺序赋值多个参数,位置参数优先接收,然后缺省参数接收数据,多余的参数被args以元组形式打包接收
# 思考:为什么要设置缺省参数呢? 一般情况下,缺省参数是不进行赋值的,因为绝大多数情况下都会赋默认值,极少情况下会使用关键字参数赋值
# 如果放到*args之前,是不是每次给*args赋值,都要给缺省参数赋值,所以不是很方便
# 综上考虑,我们决定将缺省参数放到*args之后

# def func2(a, b, c=10, *args):
#     print(a)
#     print(b)
#     print(c)
#     print(args)
# 传值逻辑如下:1.先给位置参数赋值 2.多余的未接收数据,被args打包为一个元组进行接收 3.缺省参数一般情况下不赋值,如果需要赋值,使用关键字参数赋值
# 在官方文档或者系统模块中,都是这种顺序书写的
# def func2(a, b, *args, c=10):
#     print(a)
#     print(b)
#     print(c)
#     print(args)
#
#
# func2(1, 2, 3, 4, 5)


# 结论:在定义函数时,先写位置参数,再写位置不定长参数,最后写缺省参数


# 位置参数,缺省参数,位置不定长参数,关键字不定长参数之间的位置关系

# def func2(a, b, *args, c=10, **kwargs):
#     print(a)
#     print(b)
#     print(c)
#     print(args)
#     print(kwargs)
#
#
# func2(1, 23, 4, 5, 3, 2, c=1, name='xiaoming', age=18)

# 思考:**kwargs可不可以往前放
# **kwargs只能放到最后,否则会报错

# 结论:形参排布顺序为:位置参数>>位置不定长参数>>缺省参数>>关键字不定长参数


# 调用函数时:实参

def sum1(a, b):
   print(a + b)

# SyntaxError: positional argument follows keyword argument
# 顺序赋值,不能在关键字赋值之后
# sum1(a=1, 2)

# 结论,调用参数时,先使用顺序赋值,后使用关键字赋值
posted @ 2021-08-05 20:05  蕊在花中  阅读(422)  评论(0)    收藏  举报