为什么要使用函数?
1. 组织结构混乱,可读性差
2. 代码冗余
3. 无法统一管理,维护难度极大
对函数的定义:
具备某一功能的工具即函数
函数的使用的必须遵循:先定义,后调用
函数的分类:
1 内置函数:python解释器自带的函数,python解释器启动就会定义好这些函数
len()
max()
min()
sum()
2 自定义函数
语法:
def 函数名(参数1,参数2,...):
"""注释"""
函数体
return 返回值
定义阶段
def tell_tag():
print('===========')
def tell_msg(msg):
print(msg)
#调用阶段
tell_tag()
tell_tag()
tell_msg('hello world')
tell_tag()
tell_tag()
# func()
print(tell_msg)
'''
===========
===========
hello world
===========
===========
'''
2.1自定义函数:
1.函数的使用必须遵循:先定义,后调用
2.函数的定义,就相当于在定义一个变量,如果没有定义而直接调用,就相当于在引用一个不存在的变量名
#定义阶段 def foo(): print('from foo') bar() #调用阶段 foo() #定义阶段 def bar(): print('from bar') def foo(): print('from foo') bar() #调用阶段 foo() 定义阶段 def foo(): print('from foo') bar() def bar(): print('from bar') 调用阶段 foo()
2.2 定义函数的三种方式:
无参 def main(): while True: user=input('>>: ').strip() # if len(user) == 0:continue if not user:continue password=input('>>: ') res=auth(user,password) if res: print('login successful') else: print('logon err') 有参:函数体的代码,需要外部传入的值 def auth(user,pwd): if user == 'egon' and pwd == '123': return True else: return False main() def my_max(x,y): if x > y: return x else: return y res=my_max(1,3) print(res) 空函数 def select(sql): ''' 查询功能 :param sql: 格式后的sql :return: xxxx ''' pass def update(): pass def insert(): pass def delete(): pass
3.函数的调用:
1 调用函数:函数名(), 需要注意:先通过名字找到函数的内存地址,然后加括号调用 2 函数的返回值return 注意的第一点: 在调用函数的过程中,一旦执行到return,就会立刻终止函数,并且把return后的结果当做本次调用的返回值返回 函数体内可以有多个return,但是只能执行一次 def foo(): print('111') return 1 print('2222') return 2 print('3333') return 3 res=foo() print('函数调用完毕',res) 注意的第二点: 返回的值,可以是任意类型 注意的第三点: 没有return:默认返回None 可以返回一个值===>值 可以用逗号分隔,返回多个值===>tuple def foo(): return None res=foo() print('函数调用完毕',res,type(res))
3,1调用函数的三种形式
def foo(): print('from foo') return 123 foo() res=foo() print(res) res=foo()*10 print(res)
4.函数的参数:
1:形参与实参
形参:在函数定义阶段,括号内定义的参数的称为形参,就相当于变量名
实参:在函数调用阶段,括号内定义的参数的称为实参,就相当于变量值
在调用阶段,实参的值会绑定给形参,在调用结束后,解除绑定
def foo(x,y): #x=1,y=2 print(x,y) foo(1,2)
4.1参数的分类:
一:位置参数
位置形参:必须被传值的参数,多一个不行,少一个也不行
位置实参:从左到右依次赋值给形参
def foo(x,y):
print(x,y)
foo(1,2)
二:关键字参数:在函数调用阶段,按照key=value的形式定义实参
可以不依赖位置而指名道姓地给形参传值
需要注意的问题(可以与位置实参混用,但是):
1. 位置实参必须在关键字实参的前面
2. 不能为一个形参重传值
def foo(x,y):
print(x,y)
foo(1,2,y=20)
三:默认参数:在定义函数阶段,已经为形参赋值了,在定义阶段已经赋值,意味着在调用阶段
可以不传值
注意的问题:
1 默认参数的值,只在定义时赋值一次
2 位置形参应该在默认参数的前面
3 默认参数的值应该是不可变类型
def foo(x,y=10): print(x,y) foo(y=11,x=1) def register(name,age,sex='male'): print(name,age,sex) register('egon',18) register('wsb',18) register('alex',38,'xxxxxx') x='male' def register(name,age,sex=x): print(name,age,sex) x='female' register('alex',18) def register(name,sex='male',age): print(name,age,sex)
四:可变长参数
实参可变长度指的是:实参值的个数是不固定
而实参的定义形式无非两种:1、位置实参,2、关键字实参
针对这两种形式的实参个数不固定,相应的,形参也要有两种解决方案
*
**
位置参数,默认参数,*args,命名关键字参数,**kwargs
针对按照位置定义的溢出的那部门实参,形参:*args
def func(x,y,z,*args): #args=(4,5,6) print(x,y,z) print(args) func(1,2,3) func(1,2,3,4,5,6) func(1,2,3,*[4,5,6]) #func(1,2,3,4,5,6) func(*[1,2,3,4,5,6]) #func(1,2,3,4,5,6) func([1,2,3,4,5,6]) #func(1,2,3,4,5,6) def func(x,y,z): print(x,y,z) l=[1,2,3] func(*l)
针对按照关键字定义的溢出的那部分实参,形参:**kwargs
def foo(x,y,**kwargs): #kwargs={'a':1,'z':3,'b':2} print(x,y) print(kwargs) foo(y=2,x=1,z=3,a=1,b=2) foo(1,2,3,z=3,a=1,b=2) foo(y=1,x=2,**{'a':1,'b':2,'c':3}) #foo(x=2,y=1,c=3,b=2,a=1) foo(**{'x':1,'a':1,'b':2,'c':3}) #foo(x=1,c=3,b=2,a=1) def foo(x,y,z): print(x,y,z) dic={'x':1,'y':3,'z':1} foo(**dic) #foo(x=1,y=3,a=1) def home(name,age,sex): print('from home====>',name,age,sex) def wrapper(*args,**kwargs): #args=(1,2,3,4,5,6,7),kwargs={'c':3,'b':2,'a':1} home(*args,**kwargs) # home(*(1,2,3,4,5,6,7),**{'c':3,'b':2,'a':1}) #home(1,2,3,4,5,7,a=1,b=2,c=3) # wrapper(1,2,3,4,5,6,7,a=1,b=2,c=3) wrapper('egon',sex='male',age=19)
五:命名关键字参数(了解):
形参中,在*后定义的参数称之为命名关键字参数,
它的特性是;传值时,必须按照关键字实参的形式传值
def foo(x,y=20,*args,a=1,b): print(x,y,a,b) # foo(10,b=3) foo(10,22,33,44,a=2,b=3)
5 函数对象:
函数是第一类对象:函数可以当做数据来使用
def foo():
print('from foo')
可以被引用
f=foo
# print(f)
f()
可以当做参数传入一个函数
def wrapper(x):
# print(x)
x()
wrapper(foo)
可以当做函数的返回值
def wrapper():
return foo
f=wrapper()
print(f is foo)
可以当做容器类型的一个元素
l=[foo,1,2]
l[0]()
6.函数的嵌套:
1 函数的嵌套调用:在调用一个函数的过程中,又调用其他的函数
def max(x,y): return x if x > y else y def max4(a,b,c,d): res1=max(a,b) res2=max(res1,c) res3=max(res2,d) return res3 print(max4(1,2,3,4))
2 函数的嵌套定义:在定义一个函数内部,又定义了一个函数
def f1():
def f2():
def f3():
print('from f3')
f3()
x=1
f2()
print(x)
f1()
f2()
print(x)
7.名称空间与作用域:
名称空间:存放名字与值绑定关系的地方
内置名称空间:
存放的是:内置的名字与值的绑定关系
生效:python解释器启动
失效:Python解释器关闭
全局名称空间
存放的是:文件级别定义的名字与值的绑定
生效:执行python文件时,将该文件级别定义的名字与值的绑定关系存放起来
失效:文件执行完毕
局部名称空间
存放的是:函数内部定义的名字与值的绑定关系
生效:调用函数时,临时生效
失效:函数调用结束
加载顺序:先内置,再全局,最后局部
查找名字的顺序:先局部,再全局,最后内置
x=10 if x > 3: y=2 def foo(a,b): #a='aaaa' b='bbbb' m=11111 n=2222 def bar():pass foo('aaaa','bbbb') max=10 def f1(): max='f1' def f2(): max='f2' print(max) f2() # f1() print(max)
作用域:
全局作用域:包含内置名称空间的名字与全局名称空间的名字
全局存活,全局有效
局部作用域:包含局部名称空间的名字
临时存活,局部有效
x=1011111111111111111111111111111111111111111 def f1(a): y='fffffffffffffffffffffffffffffff1' print(locals()) print(globals()) print(globals()) print(dir(globals()['__builtins__'])) print(locals() is globals()) f1(12321312312312312312312312312312312312313213)
作用域关系,在函数定义时,就已经固定了,与调用位置无关
x=10000000000000000000000000
def f1():
def f2():
# x='123123123123123123123123123123123'
print(x)
return f2
f=f1()
# print(f)
def func():
x=123
f()
x='hello'
func()