3.函数

函数基础和函数参数

一、函数基础

1.函数定义

def  函数名(参数)'''
		函数接口
		'''
        函数体
        return  返回值
  • def:定义函数关键字

  • 函数名命名规则: 字母、数字和下划线组成,和变量命名规则一致

  • 参数:传入的参数必须放在圆括号中间,用逗号分隔

  • 函数接口:此函数功能的注释

  • return :返回值关键字,后面可以返回任意表达式,但不能是赋值语句

  • 返回值 : 待返回的值,默认返回None

2.函数调用

函数名(参数)

3.return

注意 return 和 print 的区别,return是函数的返回值,返回值可以赋值给变量,而print只是打印出来

return语句用于表示函数执行到此结束,并且返回return后面的对象,一旦函数执行过程遇到return语句,那么之后函数体内的所有代码都会被忽略,直接跳出函数体,哪怕正在一个循环内

二、函数参数

1.参数

(1).位置参数

位置参数也叫必传参数,顺序参数,按照位置关系,一一对应

def my_sum(a, b, c):
	res = a + b + c
	return res
sum = my_sum(1, 2, 3)
print(sum)	# 6

a, b, c: 形式参数,简称形参

1, 2, 3: 实际参数,简称实参

(2).默认参数

默认参数必须写在位置参数的后面

def my_sum(a, b, c=666):
	res = a + b + c
	return res
sum = my_sum(1, 2)
print(sum)	# 669		

c=666: 默认参数,调用的时候如果没有传入参数,就用默认值,有实参就覆盖

(3).关键字参数

my_sum(c = 1, a = 2, b = 3): 关键字参数,函数参数会按照关键字去找对应的值,不需要位置一一对应

(4).动态参数

动态参数,必须放在所有的位置参数和默认参数后面,*args必须出现在**kwargs之前

def my_sum(*args, **kwargs):
	res = args
    kes = kwargs
    return res, kes
sum = my_sum(1, 2, b = 23, c = 43)
print(sum)	# ((1, 2), {'b': 23, 'c': 43})

动态参数:函数接受参数的个数是动态的,关键是一个和两个星号的区别

一般写法:def f(*args, **kwargs)

*args: 所有多余的位置参数都会被args接收生成一个元组

**kwargs: 所有的关键字形参都会被kwargs接收生成一个字典

2.拓展

(1).为动态参数传入列表、元组
def f(*args):
    print(args, type(args))

L = [1, 2, 3]
# 把整个列表当做一个元素传进去
f(L)		# ([1, 2, 3],) <class 'tuple'>
f(L, 4)		# ([1, 2, 3], 4) <class 'tuple'>
# 把列表内部元素逐一作为参数传进去
f(*L, 4)	# (1, 2, 3, 4) <class 'tuple'>
(2).为动态参数传入字典
def f(**kwargs):
    print(kwargs, type(kwargs))

D = {"a" : 1, "b" : 2}
# 把字典内部元素逐一作为参数传进去,不加**报错
f(**D)	# {'a': 1, 'b': 2} <class 'dict'>
(3).形参位置规定关键字参数

关键字参数前面需要一个特殊分隔符*和位置参数及默认参数分隔开来,*后面的参数被视为关键字参数

在函数调用时,关键字参数必须传入参数名,如果没有传入参数名,调用将报错

def student(name, age, *, sex):
    pass

student("zzh", 18, sex='male')

如果函数定义中已经有了*args参数,后面跟着的命名关键字参数就不再需要特殊分隔符*

def student(name, age=10, *args, sex):
    pass

student(name="zzh", age=18, sex='male')

关键字参数可以设置默认值,想要修改默认值,必须传入参数名

def func(a, b, *args, c=1):
    print(a, b, c)	# 1 2 3
    print(args)		# ('q', 'w', 'e')

lis = ["q", "w", "e"]
func(1, 2, *lis, c=3)

否则,它将被视为*args的参数

def func(a, b, *args, c=1):
    print(a, b, c)	# 1 2 1
    print(args)		# ('q', 'w', 'e', 3)

lis = ["q", "w", "e"]
func(1, 2, *lis, 3)
(4).函数名加括号被当做参数

实质是先调用函数,再将它的返回值当做别的函数的参数

三、匿名函数:lambda函数

1.语法规则

lambda   参数 : 表达式 

lambda只是一个表达式,而不是一个代码块

2.不带参数

f1 = lambda : 123
# 等效于
def f1():
    return 123

3.带参数

f2 = lambda a, b: a + b
# 等效于
def f2(a, b):
    return a + b

4. 拓展

(1).嵌套匿名函数
f = lambda a, b, func : func(a, b)
f1 = lambda a, b : a + b
f2 = lambda a, b : a - b
y1 = f(1, 2, f1)
y2 = f(1, 2, f2)
print(y1)	# 3
print(y2)	# -1
(2).实现输入匿名函数执行
f = lambda a, b, fun : fun(a, b)
func_new = input("请输入一个匿名函数:")
func_new = eval(func_new)
y = f(1, 2, func_new)
print(y)
********************************************************************
请输入一个匿名函数:lambda a, b : a + b
3
(3).实现输入匿名函数循环执行
f = lambda a, b, fun : fun(a, b)
while True:
    flag = input("请选择是否继续,q,退出;其他,继续:")
    if flag == "q":
        print("结束运行")
        break
    else:
        func_new = input("请输入一个匿名函数:")
        func_new = eval(func_new)
        y = f(1, 2, func_new)
        print(y)
********************************************************************
请选择是否继续,q,退出;其他,继续: 
请输入一个匿名函数:lambda a, b : a + b
3
请选择是否继续,q,退出;其他,继续:q
结束运行

四、作用域

作用域指的是变量的有效范围,Python查找变量顺序:局部–>局部外的局部(闭包)–>全局–>内建

1.局部变量

函数内部定义的变量,为局部变量,函数外无法调用,只能在其被声明的函数内部访问,作用域是局部作用域

在函数内部要修改一个变量,那么这个变量必须是内部变量,除非提前声明为外部变量

2.全局变量

函数外定义的变量,为全局变量,作用域是全局作用域

3.在函数内部定义全局变量

全局作用域,不能在函数内修改,想要在函数内进行修改时

global 变量名

4.函数嵌套情况

函数嵌套时,内层函数想要使用或修改外部的函数变量

nonlocal 变量名

5.注意

重点:Python函数的作用域取决于其函数代码块在整体代码中的位置,而不是调用时机的位置

name = 'jack'

def f1():
    name='tom'

    def f2():
        name ='mary'
        print(name)

    f2()

f1()	# mary
name ='jack'

def f1():
    print(name)

def f2():
    name = 'eric'
    f1()

f2()	# jack

五、闭包

1.嵌套

嵌套:我们再f1函数内又定义了一个函数,我们在调用f1函数,f1函数内部又会调用f2函数,这种形式就叫做嵌套

# 定义f1——调用f1——print(f1)——定义f2——调用f2——print(f2)
def f1():
    print("f1外层函数")
    def f2():
        print("f2内层函数")
    return f2()
f1()
********************************************************************
f1外层函数
f2内层函数

2.函数名即变量名

def f1():
    print("f1外层函数")
a = f1
a()							
********************************************************************
f1外层函数

3.闭包

函数里面嵌套函数,外层函数返回内层函数的函数名,这种情况叫做闭包

# 不带参数
def f1():
    print("f1外层函数")
    def f2():
        print("f2内层函数")
    return f2
#f1()				#f1外层函数
y = f1()			# y=f2
print(y)			# f2的地址
y()					# 调用f2()函数
********************************************************************
f1外层函数
<function f1.<locals>.f2 at 0x0000020E25977510>
f2内层函数

1.直接调用了f1函数,此时,执行print,定义了一个f2函数,同时返回了f2的函数名

2.用变量名y接收f2的函数名

3.变量名+(),实现了函数的调用

# 带参数
def f1(num1):
    print("f1外层函数", num1)
    def f2(num2):
        print("f2内层函数", num2)
    return f2
a = f1(666)				# a = f2
a(888)
********************************************************************
f1外层函数, 666
f2内层函数, 888

4.总结

1.函数内的变量外部访问不了

2.函数执行完毕后,函数内的变量会被销毁

3.需求:执行完函数后,我们需要保留函数中的某个变量

4.处理:在函数内部去定义一个函数,用内部函数去保存这个变量,我们将内层函数的函数名,当做返回值返回,不调用

5.此时内层函数就把这个需要保留的变量包含在了它的内存空间,这就是闭包

六、递归(慎用)

1.简介

  • 递归函数是指一个函数在内部调用了自身,使用时类似于条件循环一样,但是必须要有递归的终止条件
  • 递归会占用比较多的内存,当递归次数比较多时,性能就会降低,因此不建议多使用递归
  • 递归优点:代码简洁,逻辑清晰
  • 递归的核心思想:每一次递归,整体问题都要比原来减小,并且递归到一定层次时,要能直接给出结果

2.递归程序步骤

1.初始化算法

2.检查要处理的当前值是否已经与基线条件相匹配

3.使用更小的或更简单的子问题(或多个子问题)来重新定义答案

4.对子问题运行算法

5.将结果合并入答案的表达式

6.返回结果

3.举例

# 阶乘
def factorial(n):
	if n == 1:
		return 1
	return factorial(n-1)*n
a = factorial(3)
print(a)	# 6
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值