1.为什么用函数
1.代码冗余,程序组织结构不清晰,可读性差。
2.扩展性差。
2.如何让使用函数
原则:先定义后使用。
定义不会执行,但是会检查语法错误。
函数名指向内存地址存储代码信息。
先通过函数名找到函数的内存地址,然后函数内存地址的()触发代码的运行,通过returun控制返回值,可以有多个return但只能执行一次(函数立即停止)
return的返回值分为三类:
(1)返回一个值,return 1 #返回1
(2)返回多个值,return 值1,值2,值3 返回一个元组
(3)没有返回值,
①return 结束函数返回值为None
②不写 相当于在函数结尾写return None
3.函数类型
三种类型 :无参函数,有参函数,空函数
三种形式
1.语句形式 print(‘hello’)。
2.表达式形式 res = input(’>>:’)。
3.可以把函数调用当作参数传给另外一个函数。
函数参数:
1.形参:在函数定义阶段括号内定义的变量名,称为形式参数,简称形参。
2.实参:在函数调用阶段括号内传入的值,称之为实际参数,简称实参。
详解
1.位置形参:在函数定义阶段按照从左往右的顺序依次定义的形参,称之为位置形参。
特点:必须被传值,多一个不行,少一个也不行。
2.默认形参:在函数定义阶段已经为了某个形参赋值,称之为默认参数。
特点:在调用阶段可以不为其赋值。
注意:
1.默认形参的值只在函数函数定义阶段被赋值。
2.默认参数的值通常应该是不可变类型。
#例一:
m = 100
def func(x,y = m):
print(x,y)
m=200
func(1) #1 100
注意:不同参数类型可以混用,但是位置形参必须在默认形参前。
1.位置实参:在函数定义阶段按照从左往右的顺序依次定义的实参,称之为位置实参。
特点:按位置与形参一一对应。
2.关键字实参:在函数调用阶段按照key = value的方式为某个实参赋值,称之为关键字实数。
特点:可以打乱顺序但是依然能为指定的形参赋值。
4.* 与 ** 在形参与实参中的应用
可变长的参数:可变产的参数是指在函数调用阶段,实参的个数不固定,而实参是为形参赋值的。所以对应着必须一种特殊格式的形参,能用来接受溢出的实参。
形参中带*,*会接收溢出的位置参数,然后存成元组,然后赋值给紧跟其后的变量名。
形参中带 * *,会接受溢出的关键字参数,然后将其存成字典,然后复制给其后的变量名。
*args,*kwargs
实参中带 * ,后面跟的必须是一个可以被循环遍历的类型,*会将实参打算成为位置实参。
实参中带 **,后跟的必须是一个字典, **会将实参打散成关键字实参。
def func(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs):
func(*args,**kwargs)
wrapper(1,2,z=5)
5.命名关键字参数
在 * 与 ** 之间,必须用key = value的方式命名。
def func(x,y,*args,z=333):
6.type hinting
一般规则是在参数后面加冒号:(name:str)
7.名称空间
名称空间三大类:
1.内置名称空间:存的是Python解释器自带的名字。
2.全局名称空间:顶级定义的变量名。
3.局部名称空间:存的是函数内变量名。
#LEGB
L 当前 E 外层 G 全局 B 内置
总结:
1.访问优先级,L->E->G->B。
2。名称空间的‘嵌套’关系是在函数定义阶段,扫描语法时形成的,与调用位置无关。
8.作用域
全局作用域:内置名称空间、全局作用空间。
1.全局存活
2.全局有效
局部作用域:局部名称空间
1.临时存活
2.局部有效:函数内有效。
9.Global、Nonlocal
global:如果想在局部修改全局的名字对应的值。
#global
# x = 111
#
# def f1():
# global x
# x=222
#
# f1()
nonlocal:想修改函数外层包含的名字对应的值(不可变类型)。上一层没有就继续想上找,直到找到最外层函数,最后找不到会报错。
#nonlocal
# x = 0
# def f1():
# x=1
# def f2():
# nonlocal x
# x=2
# f2()
# print(x)
#
# f1()
10.闭函数、包涵数、闭包函数
闭函数:被封闭起来的函数,定义函数内部的函数,闭函数的特点是只能在函数内使用。
包涵数:该函数引用了一个名字,改名字来自E层。
闭包函数:定义在函数内部的函数引用了一个来自外层函数作用域中的名字。
闭包函数的升级,结合对象:
def outter():
x = 100
def wrapper():
print(x)
return wrapper
f=outter()
f()
为函数整体传参有两种解决方法:
一、直接以参数的形式传入
def wrapper(x):
print(x)
wrapper(666)
二、包含
def outter():
x=100
def wrapper():
print(x)
wrapper()
outter()
11.装饰器-闭包函数的应用
装饰器指的是装饰别人的工具,装饰指的是违背装饰着添加新功能,实现装饰器必须遵循的原则:‘开放封闭原则’。
开放指的是对拓展的新功能是开放的。
封闭是指对修改源码以及调用方式是封闭的。
综上,装饰器指的是我们要创建一个工具,该工具可以在原则1和2下还能为装饰对象添加新功能。
原则1:不修改装饰对象源码。
原则2:不修改被装饰对象调用方式。
为什么用装饰器:再发现问题是可以快速回滚。
怎么用:装饰器->函数 ,被装饰者->函数
装饰器语法糖:@xxx
例 @outter #相当于 index = outter(index)
模板:
def deco(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
12.有参装饰器
有参装饰器:
# def outter2(mode):
# def outter(func):
# def wrapper(*args,**kwargs):
# name = input('请输入用户名:')
# pwd = input('请输入密码:')
# if name == 'ml' and pwd == '123':
# if mode == 'file':
# print('基于文件的认证')
# else:
# print('基于数据库的认证')
# res = func(*args, **kwargs)
# return res
# else:
# print('登陆失败')
# return wrapper
# return outter
# #outter2('oracl',111,222)
# @outter2('oracl')
# def index():
# print('from index')
#
# index()
@wraps:
# from functools import wraps
#
# def deco(func):
# @wraps(func) # 加在最内层函数正上方
# def wrapper(*args, **kwargs):
# '''怎么是你?'''
# return func(*args, **kwargs)
#
# return wrapper
#
# @deco
# def index():
# '''哈哈哈哈'''
# print('from index')
#
# print(index)
# index = deco(index)
# print(index)
#
# print(index.__doc__,index.__name__)