小甲鱼python学习笔记之函数(一)

函数可以重复的实现某个功能,减少代码冗余;可以将不同功能的代码进行封装,简化代码结构,提高代码可读性。

函数的打包和调用

>>> def myfunc():
	pass

>>> myfunc()
>>> def myfunc():
	for i in range(3):
		print("I LOVE")

		
>>> myfunc()
I LOVE
I LOVE
I LOVE
 def myfunc(name):
	for i in range(2):
		print("I Love {}".format(name))

		
>>> myfunc("Pyhton")
I Love Pyhton
I Love Pyhton
>>> 
>>> def myfunc(name,time):
	for i in range(time):
		print("I love {}".format(name))

		
>>> myfunc("Pyhotn",4)
I love Pyhotn
I love Pyhotn
I love Pyhotn
I love Pyhotn

函数的返回值

def div(x,y):
	return x/y

>>> div(4,2)
2.0
>>> def div(x,y):
	if y==0:
		return "被除数不能为零"
	else:
		return x/y

	
>>> div(2,0)
'被除数不能为零'
>>> div(6,3)
2.0

如果一个函数没有通过return来显示的返回内容,那么他也会自己在执行完函数体中的所有语句之后,返回一个None值

def myfunc():
	pass

>>> print(myfunc())
None

函数的实参和形参

定义函数时的参数为形参,调用函数时传入的值为实参

函数的参数

参数就是接口,只要按照函数的要求将指定的参数正确的传递进去,函数就可以返回正确的结果。Python有多种参数。

位置参数

根据形参定义的位置传递实参

def myfunc(s,vt,o):
	return "".join((o,vt,s))

>>> myfunc("我","爱","中国")
'中国爱我'
>>> myfunc("中国","爱","我")
'我爱中国'

关键字参数

根据参数的名字(形参名)传递参数进去,位置顺序可以忽略。

>>> def myfunc(s,vt,o):
	return "".join((o,vt,s))

>>> myfunc(o="我",vt="打了",s="小甲鱼")
'我打了小甲鱼'

== 位置参数必须在关键字参数之前,否则会报错==

>>> myfunc(o="我","清蒸","xiaojiayu")
SyntaxError: positional argument follows keyword argument
>>> myfunc("清蒸","鱼",o="我")
'我鱼清蒸'

默认参数

函数定义时给形参赋一个值,如果调用函数时没有给这个参数传递实参进去,就默认使用定义时赋的值。

>>> def myfunc(s,vt,o="yu"):
	return "".join((o,vt,s))

>>> myfunc("香蕉","吃")
'yu吃香蕉'

使用help查看函数文档

使用help()函数来查看函数文档时,经常会在函数的原型中看到一个斜杠(’ / ‘),斜杠左侧的参数必须传递位置参数,而不能使用关键字,星号(’ * ')表示左侧既可以是位置参数,也可以是关键字参数。

>>> help(abs)
Help on built-in function abs in module builtins:

abs(x, /)
    Return the absolute value of the argument.

>>> help(sum)
Help on built-in function sum in module builtins:

sum(iterable, /, start=0)
    Return the sum of a 'start' value (default: 0) plus an iterable of numbers
    
    When the iterable is empty, return the start value.
    This function is intended specifically for use with numeric values and may
    reject non-numeric types.

>>> abs(-1.5)
1.5
>>> abs(x=-1.5)
Traceback (most recent call last):
  File "<pyshell#57>", line 1, in <module>
    abs(x=-1.5)
TypeError: abs() takes no keyword arguments
>>> sum([1,2,3],start=4)
10
>>> def abc(a,/,b,c):
	print(a,b,c)

	
>>> abc(3,b=4,c=8)
3 4 8

自己也可以这样定义函数以及参数

def abc(a,*,b,c):
	print(a,b,c)

	
>>> abc(1,b=2,c=4)
1 2 4
>>> abc(a=1,b=2,c=4)
1 2 4
>>> print("我","爱","Python")
我 爱 Python
>>> def myfunc(*args):
	print("有{}个参数".format(len(args)))
	print("第2个参数是,{}".format(args[1]))

	
>>> myfunc("小甲鱼","不二入市")2个参数
第2个参数是,不二入市
>>> myfunc(1,2,3,4,5)5个参数
第2个参数是,2

收集参数

参数的打包

  1. 打包为元组
    函数不知道用户需要传入多少个参数,比如print()函数可以支持参数可多可少的情况,拥有这种特性的形参称为收集参数。它的本质是元组,使用元组打包和解包的特性。
>>> def myfunc(*args):
	print(type(args))

	
>>> myfunc()
<class 'tuple'>

如果在收集参数之后还需要指定其他参数,那么在调用函数是,就应该使用关键字参数来指定后面的参数,否则Python就会把实参纳入到收集参数中:

>>> def myfunc(*args,a,b):
	print(args,a,b)

	
>>> myfunc(1,2,3,4,5)
Traceback (most recent call last):
  File "<pyshell#103>", line 1, in <module>
    myfunc(1,2,3,4,5)
TypeError: myfunc() missing 2 required keyword-only arguments: 'a' and 'b'
>>> myfunc(1,2,3,a=4,b=5)
(1, 2, 3) 4 5
  1. 打包为字典
    除了上面的将实参打包为元组,还可以将实参打包为字典
def myfunc(**kwargs):
	print(kwargs)

	
>>> myfunc(a=1,b=2,c=3)
{'a': 1, 'b': 2, 'c': 3}
  1. 还可以将其混合起来,既包含元组也包含字典,如字符串的format方法
>>> def myfunc(a,*b,**c):
	print(a,b,c)

	
>>> myfunc(1,(1,2,3),c="Pyhon")
1 ((1, 2, 3),) {'c': 'Pyhon'}
>>> myfunc(1,2,3,4,5,x=5,y=6)
1 (2, 3, 4, 5) {'x': 5, 'y': 6}
>>> help(str.format)
Help on method_descriptor:

format(...)
    S.format(*args, **kwargs) -> str
    
    Return a formatted version of S, using substitutions from args and kwargs.
    The substitutions are identified by braces ('{' and '}').

参数的解包

在形参上使用称为参数的打包,在实参上使用称为解包

args=(1,2,3,4)
>>> def myfunc(a,b,c,d):
	print(a,b,c,d)

	
>>> myfunc(args)
Traceback (most recent call last):
  File "<pyshell#125>", line 1, in <module>
    myfunc(args)
TypeError: myfunc() missing 3 required positional arguments: 'b', 'c', and 'd'
>>> myfunc(*args)     //解包为元组
1 2 3 4
>>> kwargs={'a':1,'b':2,'c':3,'d':4}
>>> myfunc(kwargs)
Traceback (most recent call last):
  File "<pyshell#128>", line 1, in <module>
    myfunc(kwargs)
TypeError: myfunc() missing 3 required positional arguments: 'b', 'c', and 'd'
>>> myfunc(**kwargs)  //解包为字典
1 2 3 4

作用域

作用域是指一个函数可以被访问的范围,由代码中被赋值的位置来决定的

局部作用域

若一个变量被赋值在函数的内部,作用域仅限于该函数中,称为局部变量

全局作用域

若在函数中存在一个跟全局一模一样的局部变量,该全局变量在函数内部可以访问但是不可以修改它的值。

>>> def myfunc():
	return 1,2,3

>>> myfunc()
(1, 2, 3)
>>> x,y,z=myfunc()
>>> x
1
>>> y
2
>>> z
3
>>> def myfunc():
	x=520
	print(x)

	
>>> myfunc()
520
>>> print(x)
1
>>> id(x)
1798563588400
>>> def myfunc():
	x=520
	print(id(x))

	
>>> myfunc()
1798603569936

若要在函数内部修改全局变量的值,需要使用global进行声明

>>> def myfunc():
	global x
	x = 520
	print (x)

	
>>> myfunc()
520

嵌套函数

调用内部函数只能通过外部函数来调用

>>> def A():
	x=520
	def funB():
		x = 880
		print("in funB,x={}".format(x))
	print("in funA,x=",x)

>>> A()
in funA,x= 520
>>> def A():
	x=520
	def funB():
		x = 880
		print("in funB,x={}".format(x))
	funB()
	print("in funA,x=",x)

	
>>> A()
in funB,x=880
in funA,x= 520	

在内部函数中修改外部函数的变量时需要使用nonlocal进行声明

>>> def A():
	x=520
	def funB():
		nonlocal x
		x = 880
		print("in funB,x={}".format(x))
	funB()
	print("in funA,x=",x)

	
>>> A()
in funB,x=880
in funA,x= 880

LEGB规则

英文名称作用域范围注释/说明
LLocal局部作用域————
EEnclosed嵌套函数的外层函数作用域在嵌套函数中,局部作用域会覆盖外层函数的作用域,需要使用nonlocal进行声明
GGlobal全局作用域当局部作用域与全局作用域发生冲突时,Python会使用局部作用域的变量,除非使用Global进行声明
BBuild In内置作用域避免使用Python的BIF内置函数作为变量名

闭包

在嵌套函数中,有两种方式可以调用内部函数:

  • 通过外部函数来调用内部函数
>>> def A():
	x=520
	def funB():
		nonlocal x
		x = 880
		print("in funB,x={}".format(x))
	funB()   
	print("in funA,x=",x)

	
>>> A()     //通过外部函数来调用内部函数
in funB,x=880
in funA,x= 880
  • 不通过外部函数来调用内部函数(函数指针)
>>> def funA():
	x=880
	def funB():
		print(x)
	return funB

>>> funA()
<function funA.<locals>.funB at 0x000001A2C5232790>   //得到一个funB的引用
>>> funA()()
880
>>> f=funA()        //调用funA()将这个变量赋给一个函数
>>> f()
880

上面的代码出现了一个神奇的现象:外部函数中定义的变量在外部函数调用完之后就没有意义了(funA函数中定义的变量x在f=funA()语句执行完之后就没有意义了),但是还是可以通过调用内部函数打印它( x )的值。

对于嵌套函数来说,外层函数的作用域是会通过某种形式给保存下来的,尽管这个函数已经调用完了,但是外层作用域的变量会保存下来,不会像局部作用域一样调用完就消失了

定义

闭包 也称为工厂函数,根据上述现象利用嵌套函数来实现类似工厂的功能。

>>> def power(exp):
	def exp_of(base):
		return base ** exp
	return exp_of

>>> square = power(2)    //嵌套函数的外部作用域会被保存下来,在执行该语句时,square指向exp_of这个内部函数,这个函数就记住了外层函数作用域的参数exp=2
>>> cube = power(3)     //cube变量指向exp_of这个函数,这个内部函数记住了exp=3
>>> square(2)
4
>>> square(5)
25
>>> cube(2)
8
>>> cube(5)
125

外部函数power相当于一个工厂,由于参数不同,得到了两条不同的生产线

  1. square 返回参数的平方
  2. cube 返回参数的立方

用法

使用nonlocal语句可以让嵌套函数的内层函数修改外层函数的变量

>>> def outer():
	x = 0
	y = 0
	def inner(x1,y1):
		nonlocal x,y
		x += x1
		y += y1
		print(f"现在,x = {x}, y = {y}")
	return inner

>>> move = outer()
>>> move(1,2)
现在,x = 1, y = 2
>>> move(-2,2)
现在,x = -1, y = 4

利用内层函数能够记住外层函数作用域这一特性,且使用nonlocal语句,让内层函数修改外层函数作用域中的变量,实现了带记忆功能的函数。

闭包的两个特性

  • 利用嵌套函数的外层作用域具有记忆功能的特性,让数据保存在外层函数的参数或者变量中
  • 将内层函数作为返回值返回,从外部函数间接调用内层函数

装饰器

既然函数可以作为返回值返回,那么是否可以把函数作为参数传递给另一个函数

>>> import time
>>> def time_master(func):
	print("开始运行程序")
	start=time.time()
	func()
	stop=time.time()
	print("程序结束运行")
	print(f"一共耗费了{(stop-start):.2f}秒。")

	
>>> 
>>> def myfunc():
	time.sleep(2)
	print("Hello World")

	
>>> time_master(myfunc)   //将函数作为参数传递给另一个函数
开始运行程序
Hello World
程序结束运行
一共耗费了2.04秒。

可是如果每次求一个函数的运行时长都要显示的调用time_master函数显然不是最优的解决方案。

改进方案:通过使用装饰器,实现调用my_func()函数时,能够自觉的执行time_master()函数
在这里插入图片描述
在代码没有显示的调用time_master()函数,但是运用结果与调用的相同

装饰器在实际开发场景中的应用

  插入日志、添加性能测试或要求先进行权限验证是,就可以通过装饰器在不修改原代码的情况下实现这些功能。

装饰器的原理和本质

  装饰器的本质是闭包,将函数作为一个参数,类似于语法糖(fstring中提过,语法糖为某种特殊的语法,对函数的功能本身无影响,但是更加简洁)
在这里插入图片描述

多个装饰器可以用在同一个函数上

代码如下:

//1
def add(func):
    def inner():
        x=func()            //令x=64,返回64+1
        return x+1
    return inner
//立方
def cube(func):
    def inner():
        x=func()           //令x=4,返回4的立方
        return x*x*x
    return inner
//平方
def square(func):
    def inner():
        x=func()
        return x*x
    return inner

@add
@cube
@square
def test():
    return 2  //装饰器由内向外执行,将test作为参数塞到square这个装饰器中运行,令x=2,返回2的平方

print(test())

代码执行结果如下:
在这里插入图片描述

给装饰器传递参数

多加一层函数嵌套,添加一次调用,通过这次调用将参数传递进去
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值