函数定义:
def 函数名( 参数) :
函数内容
return 返回值
函数调用:
函数名()
1.return 可以没有,返回值就默认为None
2.可以return 多个值,以元组形式返回
def function(a,b):
return a + b
if __name__ == '__main__':
print(function(12,16))#28
函数参数
形参 def function(**a,b**)
实参 function(**12,16**)
参数的传递:
1.按位置传递参数
2.按关键字传参
3.混合传参
函数中参数类型:function(a,b)
1.普通参数
2.默认参数
3.可变参数
4.关键字的可变参数
5.keyword-only参数
参数传递顺序一般为:位置参数,可变参数,默认参数,可变的关键字参数
def function(a,b):#按位置传递普通参数
print(a)#20
print(b)#10
def f():
a = 10
b = 20
function(b,a) #function(20,10)
'''
参数个数必须一致
'''
def function(a,b):#按关键字传递普通参数
print(a)
print(b)
def f():
a = 10
function(a,b=15)#function(位置参数,关键字参数)
'''
1.位置参数要在关键字参数之前,否则报错
2.同一个参数不能传递2次
function(10,a=10)
10已经按照位置传参的方式传给了a
又来一个关键字传参给a 所以会报错
'''
默认参数:
def function(a='一'):#默认值参数,不给参数就使用默认参数
print('今天是星期%s'%a)
function()
可变参数:
参数个数不确定,以元组形式存放,按位置接受
def function(a,*args):#按位置传递普通参数,可变参数
print(args)#<class 'tuple'>
num = 0
for i in args:
num += i
print(num)#18
def f():
function(2,6,4,8)
关键字的可变参数:
def function(**args):#关键字的可变参数,以字典形式存放
for i in args :#以字典形式存放,所以取出的都是key
print(i)# a b c
function(a=1,b=2,c=3)
'''
默认参数要在关键字参数之前
def function(args = True,**args):
'''
参数的解构:
对于list,dict作为参数时,可以将参数解构,一个一个的传入
def function(args):
print(args)#[2, 3, 4, 5, 6]
print(type(args))#<class 'list'>
li = [2,3,4,5,6]
function(li)
#参数解构
def f1(*args):
print(args)#(2, 3, 4, 5, 6)
print(type(args))#<class 'tuple'>
li = [2,3,4,5,6]
f1(*li)
python3新加入的keyword-only参数
在函数中,可变参数后面出现的普通参数是keyword-only参数,必须以关键字传参的方式传递
def f1(*args,a,b):
return a+b
print (f1(2,3,5,a = 1,b =5))#6
'''
keyword-only参数必须在**args可变的关键参数之前,因为**args会拦截所有传入的关键字方式传参
def foo(a,*args,x,y,**kwargs)
'''
参数传递的陷阱问题:
def f1(l=[]):
l.append(10)
print(l)
f1()#[10]
l = []
f1(l)#[10]
f1()#[10, 10]
'''
f1(),无参数,就使用默认的[],此时输出[10]
f1(l)有参数,另一个[],此时输出[10]
f1(),无参数,继续使用默认的[],此时里面已经有一个10,所有结果为[10, 10]
'''
函数进阶
命名空间与作用域:
内置命名空间:随python解释器启动而加载
全局命名空间:程序从上至下执行时一次加载,存放了所有的全局变量,函数名
局部命名空间:随函数的调用而传升,结束而消亡
单纯的函数名指向一个内存地址
函数名——》内存地址
函数名()——》调用函数
#关键字global
num = 9
def f1():
if num%2 : #报错,局部变量num未定义
print('奇数')
'''
函数内部想引用全局的变量,需要关键字global
num = 9
def f1():
global num
if num%2 :
print('奇数')
注意:global存在一些安全问题,尽量少用,需要的参数建议传参的方式传入
'''
```python
#关键字nonlocal
def f1():
num = 123
def f2():
nonlocal num
num += 5
f2()
print(num)
f1()
'''
nonlocal 声明上一层的局部变量
只在局部中找上一层的变量,找不到再上一层,只在局部找
'''
查看全局,局部变量
name = '张三'
age = 23
def f():
sex = '男'
job = 'teacher'
print(locals())#查看所有的局部变量
print(globals())#查看所有全局变量
f()
'''
globals():放在全局或局部都是输出所有全局变量
locals():放在全局,输出全局变量;放在局部,输出局部变量
变量都是key-value形式的字典
全局变量中的部门元素
'__name__': '__main__'
在当前正在运行的文件中,__name__的值为_main__
调用的其他文件中有__name__,值为文件名(无后缀)
'__doc__': '....'
存放的是所有的多行注解
'__file__': 'D:\\....'
存放的是当前文件的地址
'''
函数名就是内存地址
可以赋值
可以作为容器的元素 例:globals()获取的字典中的元素 函数名 : 内存地址
可以作为参数,作为返回值
函数名是第一类对象
第一类对象
在运行期创建
可以作为函数的参数或返回值
可存入变量的实体(作为容器元素)
闭包
闭包:
1.有嵌套函数
2.内部函数调用外部函数的变量
3.内部函数作为参数返回
例:
def function():
num = 1
def f():
print(num)
return f
ret = function()
print(ret.__closure__)#(<cell at 0x0000000001ED4558: int object at 0x000007FEEDE87100>,)
ret()
'''
内部函数的属性__closure__中包含内部函数所有引用的外部变量
值为None表示非闭包
'''
装饰器
装饰器:在不修改原函数的前提下,在原函数执行前后添新功能
例:
def function(f):
def inner(*args,**kwagrs):
print('增强代码')
ret = f(*args,**kwagrs)
if type(ret) == str and ret.isalpha():
return ret.upper()
return ret
return inner
def code(s):
s += 's'
return s
code = function(code)#将函数名code作为参数传入,将得到的返回值inner 赋值给code变量,会覆盖方法名code变量
#即code = inner 这是内部函数的函数名指向一个地址
ret = code('hello')#实质是调用是调用inner('hello'),内部函数执行,执行增强代码
print(ret)#HELLOS
例:获取程序运行时间
import time
def function(f):
def inner(*args,**kwagrs):
start = time.time()
ret = f(*args,**kwagrs)
end =time.time() - start
print('程序运行时间为%.4f'% end)
#print(type(end))
return ret
return inner
def code(n):
for i in range(n):
print(i)
code = function(code)
code(10000)
装饰器:
import time
def function(f):
def inner(*args,**kwagrs):
start = time.time()
ret = f(*args,**kwagrs)
end =time.time() - start
print('程序运行时间为%.4f'% end)
#print(type(end))
return ret
return inner
@function #等价于code = function(code),改变了调用方式,增加了功能
def code(n):
for i in range(n):
print(i)
code(10000)
#在被装饰方法上加上@装饰器函数名